<!DOCTYPE html>
<html lang="zh-CN" data-theme="light">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <meta name="generator" content="VuePress 2.0.0-beta.48" />
    <meta name="theme" content="VuePress Theme Hope" />
    <meta property="og:url" content="https://vuepress-theme-hope-v2-demo.mrhope.site/zh/interview/JUC.html"><meta property="og:site_name" content="主题演示"><meta property="og:title" content="JUC"><meta property="og:type" content="article"><meta property="og:locale" content="zh-CN"><meta property="og:locale:alternate" content="en-US"><meta property="article:tag" content="JUC"><title>JUC | 主题演示</title><meta name="description" content="vuepress-theme-hope 的演示">
    <style>
      :root {
        --bg-color: #fff;
      }

      html[data-theme="dark"] {
        --bg-color: #1d2025;
      }

      html,
      body {
        background-color: var(--bg-color);
      }
    </style>
    <script>
      const userMode = localStorage.getItem("vuepress-theme-hope-scheme");
      const systemDarkMode =
        window.matchMedia &&
        window.matchMedia("(prefers-color-scheme: dark)").matches;

      if (userMode === "dark" || (userMode !== "light" && systemDarkMode)) {
        document.querySelector("html").setAttribute("data-theme", "dark");
      }
    </script>
    <link rel="stylesheet" href="/assets/style.dbbe025d.css">
    <link rel="modulepreload" href="/assets/app.e732cc94.js"><link rel="modulepreload" href="/assets/JUC.html.ebe8f287.js"><link rel="modulepreload" href="/assets/plugin-vue_export-helper.21dcd24c.js"><link rel="modulepreload" href="/assets/JUC.html.76307785.js"><link rel="prefetch" href="/assets/home.html.d675c4b6.js"><link rel="prefetch" href="/assets/intro.html.684ef626.js"><link rel="prefetch" href="/assets/index.html.e8ffec66.js"><link rel="prefetch" href="/assets/slide.html.050a6f1e.js"><link rel="prefetch" href="/assets/disable.html.b507ecac.js"><link rel="prefetch" href="/assets/encrypt.html.762116d5.js"><link rel="prefetch" href="/assets/markdown.html.5acf7a9a.js"><link rel="prefetch" href="/assets/page.html.141b0147.js"><link rel="prefetch" href="/assets/index.html.75bf4c69.js"><link rel="prefetch" href="/assets/article10.html.f5ea4d77.js"><link rel="prefetch" href="/assets/article11.html.6339c214.js"><link rel="prefetch" href="/assets/article12.html.5ac86a8f.js"><link rel="prefetch" href="/assets/article9.html.666c37a0.js"><link rel="prefetch" href="/assets/home.html.6e361c52.js"><link rel="prefetch" href="/assets/index.html.2d9b62a7.js"><link rel="prefetch" href="/assets/slide.html.6b655fa0.js"><link rel="prefetch" href="/assets/article1.html.f835efef.js"><link rel="prefetch" href="/assets/article2.html.e4775195.js"><link rel="prefetch" href="/assets/article3.html.bfdf934f.js"><link rel="prefetch" href="/assets/article4.html.69bccee4.js"><link rel="prefetch" href="/assets/article5.html.c7ac5439.js"><link rel="prefetch" href="/assets/article6.html.880c0652.js"><link rel="prefetch" href="/assets/article7.html.2cae84db.js"><link rel="prefetch" href="/assets/article8.html.6c46837c.js"><link rel="prefetch" href="/assets/disable.html.f629efab.js"><link rel="prefetch" href="/assets/encrypt.html.58d61689.js"><link rel="prefetch" href="/assets/markdown.html.779c42bf.js"><link rel="prefetch" href="/assets/page.html.125d74f5.js"><link rel="prefetch" href="/assets/index.html.3db704fb.js"><link rel="prefetch" href="/assets/article10.html.b5d65d2d.js"><link rel="prefetch" href="/assets/article11.html.b2cf93ee.js"><link rel="prefetch" href="/assets/article12.html.94e1cf22.js"><link rel="prefetch" href="/assets/article9.html.90cf2a62.js"><link rel="prefetch" href="/assets/Docker.html.de1063e8.js"><link rel="prefetch" href="/assets/Java基础.html.6c0b0f5c.js"><link rel="prefetch" href="/assets/Java容器.html.77448ff5.js"><link rel="prefetch" href="/assets/JVM.html.0bb340ff.js"><link rel="prefetch" href="/assets/Linux.html.90ea1c3b.js"><link rel="prefetch" href="/assets/MySQL.html.73ae62bf.js"><link rel="prefetch" href="/assets/NIO与Netty.html.a73529b1.js"><link rel="prefetch" href="/assets/index.html.2a38d188.js"><link rel="prefetch" href="/assets/Redis.html.78427b11.js"><link rel="prefetch" href="/assets/主流框架.html.f21f66df.js"><link rel="prefetch" href="/assets/分布式与高性能高可用.html.38ab4746.js"><link rel="prefetch" href="/assets/操作系统.html.76b600e3.js"><link rel="prefetch" href="/assets/智力题.html.ec368cec.js"><link rel="prefetch" href="/assets/系统设计.html.fb8f2074.js"><link rel="prefetch" href="/assets/计算机网络.html.1a7f7d0e.js"><link rel="prefetch" href="/assets/设计模式.html.cd48ccf5.js"><link rel="prefetch" href="/assets/article1.html.ca54de60.js"><link rel="prefetch" href="/assets/article2.html.a99d479f.js"><link rel="prefetch" href="/assets/article3.html.5a2797ee.js"><link rel="prefetch" href="/assets/article4.html.3ac5a509.js"><link rel="prefetch" href="/assets/article5.html.c09d20ba.js"><link rel="prefetch" href="/assets/article6.html.c9e59f52.js"><link rel="prefetch" href="/assets/article7.html.948e77cc.js"><link rel="prefetch" href="/assets/article8.html.28c3977f.js"><link rel="prefetch" href="/assets/404.html.8a909211.js"><link rel="prefetch" href="/assets/index.html.690b188a.js"><link rel="prefetch" href="/assets/index.html.6085d793.js"><link rel="prefetch" href="/assets/index.html.932078ca.js"><link rel="prefetch" href="/assets/index.html.bb629f30.js"><link rel="prefetch" href="/assets/index.html.92b2d70c.js"><link rel="prefetch" href="/assets/index.html.82840baf.js"><link rel="prefetch" href="/assets/index.html.85406aa8.js"><link rel="prefetch" href="/assets/index.html.7b9124b8.js"><link rel="prefetch" href="/assets/index.html.e1e2a548.js"><link rel="prefetch" href="/assets/index.html.a9a69593.js"><link rel="prefetch" href="/assets/index.html.5b51b72b.js"><link rel="prefetch" href="/assets/index.html.ec7f0295.js"><link rel="prefetch" href="/assets/index.html.e14e2286.js"><link rel="prefetch" href="/assets/index.html.e89216be.js"><link rel="prefetch" href="/assets/index.html.c0adb933.js"><link rel="prefetch" href="/assets/index.html.a45798a3.js"><link rel="prefetch" href="/assets/index.html.e99c516b.js"><link rel="prefetch" href="/assets/index.html.f6be7fb4.js"><link rel="prefetch" href="/assets/index.html.6812b391.js"><link rel="prefetch" href="/assets/index.html.4bae905e.js"><link rel="prefetch" href="/assets/index.html.0599248b.js"><link rel="prefetch" href="/assets/index.html.963b2596.js"><link rel="prefetch" href="/assets/index.html.bbd9778f.js"><link rel="prefetch" href="/assets/index.html.c6a7a8d4.js"><link rel="prefetch" href="/assets/index.html.13391f8f.js"><link rel="prefetch" href="/assets/index.html.4b0a0f3f.js"><link rel="prefetch" href="/assets/index.html.bbd06d0d.js"><link rel="prefetch" href="/assets/index.html.9a4d8710.js"><link rel="prefetch" href="/assets/index.html.dfdff039.js"><link rel="prefetch" href="/assets/index.html.cd21ad11.js"><link rel="prefetch" href="/assets/index.html.72b3c545.js"><link rel="prefetch" href="/assets/index.html.0262e65d.js"><link rel="prefetch" href="/assets/index.html.8905ca40.js"><link rel="prefetch" href="/assets/index.html.98e54f53.js"><link rel="prefetch" href="/assets/index.html.707c5120.js"><link rel="prefetch" href="/assets/index.html.daf3ede2.js"><link rel="prefetch" href="/assets/index.html.ae769b93.js"><link rel="prefetch" href="/assets/index.html.59a75e1b.js"><link rel="prefetch" href="/assets/index.html.efb1d101.js"><link rel="prefetch" href="/assets/index.html.898df6f8.js"><link rel="prefetch" href="/assets/index.html.6339ac7f.js"><link rel="prefetch" href="/assets/index.html.0ffdd311.js"><link rel="prefetch" href="/assets/index.html.454f52cf.js"><link rel="prefetch" href="/assets/index.html.d8a5ddde.js"><link rel="prefetch" href="/assets/index.html.3be06723.js"><link rel="prefetch" href="/assets/index.html.1d180388.js"><link rel="prefetch" href="/assets/index.html.337241b0.js"><link rel="prefetch" href="/assets/index.html.0be3cd3f.js"><link rel="prefetch" href="/assets/index.html.8e5505d4.js"><link rel="prefetch" href="/assets/index.html.ffdd1452.js"><link rel="prefetch" href="/assets/index.html.d3825f4c.js"><link rel="prefetch" href="/assets/home.html.ccae7996.js"><link rel="prefetch" href="/assets/intro.html.fd34d8e1.js"><link rel="prefetch" href="/assets/index.html.ba786069.js"><link rel="prefetch" href="/assets/slide.html.0df38877.js"><link rel="prefetch" href="/assets/disable.html.6465acbf.js"><link rel="prefetch" href="/assets/encrypt.html.f697c2c7.js"><link rel="prefetch" href="/assets/markdown.html.f534aa4c.js"><link rel="prefetch" href="/assets/page.html.d91d46f6.js"><link rel="prefetch" href="/assets/index.html.b66745bd.js"><link rel="prefetch" href="/assets/article10.html.a245f19a.js"><link rel="prefetch" href="/assets/article11.html.c7128e02.js"><link rel="prefetch" href="/assets/article12.html.abd25c27.js"><link rel="prefetch" href="/assets/article9.html.7bba6b9f.js"><link rel="prefetch" href="/assets/home.html.eb29b64c.js"><link rel="prefetch" href="/assets/index.html.a51898c1.js"><link rel="prefetch" href="/assets/slide.html.4db0d16b.js"><link rel="prefetch" href="/assets/article1.html.8aeaf420.js"><link rel="prefetch" href="/assets/article2.html.1b3af75b.js"><link rel="prefetch" href="/assets/article3.html.83bc62c6.js"><link rel="prefetch" href="/assets/article4.html.9c3e20ef.js"><link rel="prefetch" href="/assets/article5.html.a86dfd69.js"><link rel="prefetch" href="/assets/article6.html.1005b310.js"><link rel="prefetch" href="/assets/article7.html.e62a511b.js"><link rel="prefetch" href="/assets/article8.html.5d7e1f67.js"><link rel="prefetch" href="/assets/disable.html.9d48f34e.js"><link rel="prefetch" href="/assets/encrypt.html.69059b41.js"><link rel="prefetch" href="/assets/markdown.html.f8f89db4.js"><link rel="prefetch" href="/assets/page.html.f139635c.js"><link rel="prefetch" href="/assets/index.html.126e92a0.js"><link rel="prefetch" href="/assets/article10.html.f00bfbec.js"><link rel="prefetch" href="/assets/article11.html.4e4aea0e.js"><link rel="prefetch" href="/assets/article12.html.ed056ef8.js"><link rel="prefetch" href="/assets/article9.html.c3cb96a4.js"><link rel="prefetch" href="/assets/Docker.html.f45c96a5.js"><link rel="prefetch" href="/assets/Java基础.html.56267f30.js"><link rel="prefetch" href="/assets/Java容器.html.5139503a.js"><link rel="prefetch" href="/assets/JVM.html.c448b42c.js"><link rel="prefetch" href="/assets/Linux.html.43840acf.js"><link rel="prefetch" href="/assets/MySQL.html.eba28d84.js"><link rel="prefetch" href="/assets/NIO与Netty.html.66d42188.js"><link rel="prefetch" href="/assets/index.html.f3cc61a2.js"><link rel="prefetch" href="/assets/Redis.html.d810a669.js"><link rel="prefetch" href="/assets/主流框架.html.48ca457c.js"><link rel="prefetch" href="/assets/分布式与高性能高可用.html.a85c8cdb.js"><link rel="prefetch" href="/assets/操作系统.html.c2f0370c.js"><link rel="prefetch" href="/assets/智力题.html.4d751983.js"><link rel="prefetch" href="/assets/系统设计.html.c1542e9d.js"><link rel="prefetch" href="/assets/计算机网络.html.724e0903.js"><link rel="prefetch" href="/assets/设计模式.html.2465754d.js"><link rel="prefetch" href="/assets/article1.html.ac18bda1.js"><link rel="prefetch" href="/assets/article2.html.051f8867.js"><link rel="prefetch" href="/assets/article3.html.ebe7849b.js"><link rel="prefetch" href="/assets/article4.html.a4dbc976.js"><link rel="prefetch" href="/assets/article5.html.395a5403.js"><link rel="prefetch" href="/assets/article6.html.74c49cbf.js"><link rel="prefetch" href="/assets/article7.html.bf053e97.js"><link rel="prefetch" href="/assets/article8.html.7213c414.js"><link rel="prefetch" href="/assets/404.html.22aaa4fc.js"><link rel="prefetch" href="/assets/index.html.bd6ff77c.js"><link rel="prefetch" href="/assets/index.html.a7880d9d.js"><link rel="prefetch" href="/assets/index.html.f5f99f6a.js"><link rel="prefetch" href="/assets/index.html.561cd4cd.js"><link rel="prefetch" href="/assets/index.html.2b2206fe.js"><link rel="prefetch" href="/assets/index.html.ec6b7467.js"><link rel="prefetch" href="/assets/index.html.146ab8c4.js"><link rel="prefetch" href="/assets/index.html.f201f6e8.js"><link rel="prefetch" href="/assets/index.html.a1a6c5d4.js"><link rel="prefetch" href="/assets/index.html.61b33c23.js"><link rel="prefetch" href="/assets/index.html.8640e57f.js"><link rel="prefetch" href="/assets/index.html.c3d0fc1d.js"><link rel="prefetch" href="/assets/index.html.461f8cdf.js"><link rel="prefetch" href="/assets/index.html.1dea7bef.js"><link rel="prefetch" href="/assets/index.html.e6addda8.js"><link rel="prefetch" href="/assets/index.html.2638e7e9.js"><link rel="prefetch" href="/assets/index.html.5db2b8e8.js"><link rel="prefetch" href="/assets/index.html.cbff7fea.js"><link rel="prefetch" href="/assets/index.html.5ac21d40.js"><link rel="prefetch" href="/assets/index.html.c7acfbee.js"><link rel="prefetch" href="/assets/index.html.fb44feb1.js"><link rel="prefetch" href="/assets/index.html.d4e476c9.js"><link rel="prefetch" href="/assets/index.html.ec5764c9.js"><link rel="prefetch" href="/assets/index.html.d185c9f1.js"><link rel="prefetch" href="/assets/index.html.0867f7ab.js"><link rel="prefetch" href="/assets/index.html.2c3899c7.js"><link rel="prefetch" href="/assets/index.html.8a2aee35.js"><link rel="prefetch" href="/assets/index.html.130e4c85.js"><link rel="prefetch" href="/assets/index.html.7277b095.js"><link rel="prefetch" href="/assets/index.html.c074ddbd.js"><link rel="prefetch" href="/assets/index.html.e91a40c5.js"><link rel="prefetch" href="/assets/index.html.0b2b027d.js"><link rel="prefetch" href="/assets/index.html.6b602146.js"><link rel="prefetch" href="/assets/index.html.16d4af72.js"><link rel="prefetch" href="/assets/index.html.b8fc0dcc.js"><link rel="prefetch" href="/assets/index.html.9b3fcbd9.js"><link rel="prefetch" href="/assets/index.html.eeb89bf7.js"><link rel="prefetch" href="/assets/index.html.5114cd1e.js"><link rel="prefetch" href="/assets/index.html.b8354286.js"><link rel="prefetch" href="/assets/index.html.fcd579df.js"><link rel="prefetch" href="/assets/index.html.e743d320.js"><link rel="prefetch" href="/assets/index.html.b34f28e1.js"><link rel="prefetch" href="/assets/index.html.dd5dd927.js"><link rel="prefetch" href="/assets/index.html.7df41339.js"><link rel="prefetch" href="/assets/index.html.9de9b7ae.js"><link rel="prefetch" href="/assets/index.html.db158b25.js"><link rel="prefetch" href="/assets/index.html.fcab0b26.js"><link rel="prefetch" href="/assets/index.html.afada1db.js"><link rel="prefetch" href="/assets/index.html.8681058b.js"><link rel="prefetch" href="/assets/index.html.1c990d16.js"><link rel="prefetch" href="/assets/index.html.9563932e.js"><link rel="prefetch" href="/assets/404.4ba82410.js"><link rel="prefetch" href="/assets/Layout.67323a43.js"><link rel="prefetch" href="/assets/Slide.be972901.js"><link rel="prefetch" href="/assets/Blog.caaad5e4.js"><link rel="prefetch" href="/assets/giscus.es.63137db5.js"><link rel="prefetch" href="/assets/auto.esm.36809f22.js"><link rel="prefetch" href="/assets/index.daae04bf.js"><link rel="prefetch" href="/assets/index.1842ee54.js"><link rel="prefetch" href="/assets/mermaid.esm.min.ee1e0284.js"><link rel="prefetch" href="/assets/highlight.esm.d982e650.js"><link rel="prefetch" href="/assets/markdown.esm.832a189d.js"><link rel="prefetch" href="/assets/math.esm.a3f84b6f.js"><link rel="prefetch" href="/assets/notes.esm.3c361cb7.js"><link rel="prefetch" href="/assets/reveal.esm.b96f05d8.js"><link rel="prefetch" href="/assets/search.esm.80da4a02.js"><link rel="prefetch" href="/assets/zoom.esm.8514a202.js"><link rel="prefetch" href="/assets/photoswipe.esm.092fbc15.js">
  </head>
  <body>
    <div id="app"><!--[--><!--[--><!--[--><span tabindex="-1"></span><a href="#main-content" class="skip-link sr-only">Skip to content</a><!--]--><div class="theme-container has-toc"><!--[--><!--[--><header class="navbar"><div class="navbar-left"><button class="toggle-sidebar-button" title="Toggle Sidebar"><span class="icon"></span></button><!----><a href="/zh/" class="brand"><img class="logo" src="/logo.svg" alt="主题演示"><!----><span class="site-name hide-in-pad">主题演示</span></a><!----></div><div class="navbar-center"><!----><nav class="nav-links"><div class="nav-item hide-in-mobile"><a href="/zh/" class="nav-link" aria-label="博客主页"><span class="icon iconfont icon-home" style=""></span>博客主页<!----></a></div><div class="nav-item hide-in-mobile"><a href="/zh/home.html" class="nav-link" aria-label="项目主页"><span class="icon iconfont icon-home" style=""></span>项目主页<!----></a></div><div class="nav-item hide-in-mobile"><a href="/zh/guide/" class="nav-link" aria-label="使用指南"><span class="icon iconfont icon-creative" style=""></span>使用指南<!----></a></div><div class="nav-item hide-in-mobile"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="博文"><span class="title"><span class="icon iconfont icon-edit" style=""></span>博文</span><span class="arrow"></span><ul class="nav-dropdown"><li class="dropdown-item"><h4 class="dropdown-subtitle"><span>文章 1-4</span></h4><ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/zh/posts/article/article1.html" class="nav-link" aria-label="文章 1"><span class="icon iconfont icon-edit" style=""></span>文章 1<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article2.html" class="nav-link" aria-label="文章 2"><span class="icon iconfont icon-edit" style=""></span>文章 2<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article3.html" class="nav-link" aria-label="文章 3"><span class="icon iconfont icon-edit" style=""></span>文章 3<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article4.html" class="nav-link" aria-label="文章 4"><span class="icon iconfont icon-edit" style=""></span>文章 4<!----></a></li></ul></li><li class="dropdown-item"><h4 class="dropdown-subtitle"><span>文章 5-12</span></h4><ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/zh/posts/article/article5.html" class="nav-link" aria-label="文章 5"><span class="icon iconfont icon-edit" style=""></span>文章 5<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article6.html" class="nav-link" aria-label="文章 6"><span class="icon iconfont icon-edit" style=""></span>文章 6<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article7.html" class="nav-link" aria-label="文章 7"><span class="icon iconfont icon-edit" style=""></span>文章 7<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article8.html" class="nav-link" aria-label="文章 8"><span class="icon iconfont icon-edit" style=""></span>文章 8<!----></a></li></ul></li><li class="dropdown-item"><a href="/zh/posts/article9.html" class="nav-link" aria-label="文章 9"><span class="icon iconfont icon-edit" style=""></span>文章 9<!----></a></li><li class="dropdown-item"><a href="/zh/posts/article10.html" class="nav-link" aria-label="文章 10"><span class="icon iconfont icon-edit" style=""></span>文章 10<!----></a></li><li class="dropdown-item"><a href="/zh/posts/article11.html" class="nav-link" aria-label="文章 11"><span class="icon iconfont icon-edit" style=""></span>文章 11<!----></a></li><li class="dropdown-item"><a href="/zh/posts/article12.html" class="nav-link" aria-label="文章 12"><span class="icon iconfont icon-edit" style=""></span>文章 12<!----></a></li></ul></button></div></div><div class="nav-item hide-in-mobile"><a href="https://vuepress-theme-hope.github.io/v2/zh/" rel="noopener noreferrer" target="_blank" aria-label="主题文档" class="nav-link"><span class="icon iconfont icon-note" style=""></span>主题文档<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div></nav><!----></div><div class="navbar-right"><!----><div class="nav-item"><div class="dropdown-wrapper i18n-dropdown"><button class="dropdown-title" type="button" aria-label="选择语言"><!--[--><svg xmlns="http://www.w3.org/2000/svg" class="icon i18n-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="i18n icon" style="width:1rem;height:1rem;vertical-align:middle;"><path d="M379.392 460.8 494.08 575.488l-42.496 102.4L307.2 532.48 138.24 701.44l-71.68-72.704L234.496 460.8l-45.056-45.056c-27.136-27.136-51.2-66.56-66.56-108.544h112.64c7.68 14.336 16.896 27.136 26.112 35.84l45.568 46.08 45.056-45.056C382.976 312.32 409.6 247.808 409.6 204.8H0V102.4h256V0h102.4v102.4h256v102.4H512c0 70.144-37.888 161.28-87.04 210.944L378.88 460.8zM576 870.4 512 1024H409.6l256-614.4H768l256 614.4H921.6l-64-153.6H576zM618.496 768h196.608L716.8 532.48 618.496 768z"></path></svg><!--]--><span class="arrow"></span><ul class="nav-dropdown"><li class="dropdown-item"><a href="/" class="nav-link" aria-label="English"><!---->English<!----></a></li><li class="dropdown-item"><a aria-current="page" href="/zh/interview/JUC.html" class="router-link-active router-link-exact-active nav-link active" aria-label="简体中文"><!---->简体中文<!----></a></li></ul></button></div></div><div class="nav-item"><a class="repo-link" href="https://gitee.com/changluJava/personal-reading" target="_blank" rel="noopener noreferrer" aria-label="Gitee"><svg xmlns="http://www.w3.org/2000/svg" class="icon gitee-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="gitee icon" style="width:1.25rem;height:1.25rem;vertical-align:middle;"><path d="M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm242.97-533.34H482.39a23.7 23.7 0 0 0-23.7 23.7l-.03 59.28c0 13.08 10.59 23.7 23.7 23.7h165.96a23.7 23.7 0 0 1 23.7 23.7v11.85a71.1 71.1 0 0 1-71.1 71.1H375.71a23.7 23.7 0 0 1-23.7-23.7V423.11a71.1 71.1 0 0 1 71.1-71.1h331.8a23.7 23.7 0 0 0 23.7-23.7l.06-59.25a23.73 23.73 0 0 0-23.7-23.73H423.11a177.78 177.78 0 0 0-177.78 177.75v331.83c0 13.08 10.62 23.7 23.7 23.7h349.62a159.99 159.99 0 0 0 159.99-159.99V482.33a23.7 23.7 0 0 0-23.7-23.7z"></path></svg></a></div><div class="nav-item hide-in-mobile"><button id="appearance-switch"><svg xmlns="http://www.w3.org/2000/svg" class="icon auto-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="auto icon" style="display:block;"><path d="M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm0-840c-198.78 0-360 161.22-360 360 0 198.84 161.22 360 360 360s360-161.16 360-360c0-198.78-161.22-360-360-360zm0 660V212c165.72 0 300 134.34 300 300 0 165.72-134.28 300-300 300z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon dark-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="dark icon" style="display:none;"><path d="M524.8 938.667h-4.267a439.893 439.893 0 0 1-313.173-134.4 446.293 446.293 0 0 1-11.093-597.334A432.213 432.213 0 0 1 366.933 90.027a42.667 42.667 0 0 1 45.227 9.386 42.667 42.667 0 0 1 10.24 42.667 358.4 358.4 0 0 0 82.773 375.893 361.387 361.387 0 0 0 376.747 82.774 42.667 42.667 0 0 1 54.187 55.04 433.493 433.493 0 0 1-99.84 154.88 438.613 438.613 0 0 1-311.467 128z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="light icon" style="display:none;"><path d="M952 552h-80a40 40 0 0 1 0-80h80a40 40 0 0 1 0 80zM801.88 280.08a41 41 0 0 1-57.96-57.96l57.96-58a41.04 41.04 0 0 1 58 58l-58 57.96zM512 752a240 240 0 1 1 0-480 240 240 0 0 1 0 480zm0-560a40 40 0 0 1-40-40V72a40 40 0 0 1 80 0v80a40 40 0 0 1-40 40zm-289.88 88.08-58-57.96a41.04 41.04 0 0 1 58-58l57.96 58a41 41 0 0 1-57.96 57.96zM192 512a40 40 0 0 1-40 40H72a40 40 0 0 1 0-80h80a40 40 0 0 1 40 40zm30.12 231.92a41 41 0 0 1 57.96 57.96l-57.96 58a41.04 41.04 0 0 1-58-58l58-57.96zM512 832a40 40 0 0 1 40 40v80a40 40 0 0 1-80 0v-80a40 40 0 0 1 40-40zm289.88-88.08 58 57.96a41.04 41.04 0 0 1-58 58l-57.96-58a41 41 0 0 1 57.96-57.96z"></path></svg></button></div><!----><!----><button class="toggle-navbar-button" aria-label="Toggle Navbar" aria-expanded="false" aria-controls="nav-screen"><span class="button-container"><span class="button-top"></span><span class="button-middle"></span><span class="button-bottom"></span></span></button></div></header><!----><!--]--><!----><div class="toggle-sidebar-wrapper"><span class="arrow left"></span></div><aside class="sidebar"><!--[--><!----><!--]--><ul class="sidebar-links"><li><!--[--><a href="/zh/" class="nav-link sidebar-link sidebar-page" aria-label="博客主页"><span class="icon iconfont icon-home" style=""></span>博客主页<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/home.html" class="nav-link sidebar-link sidebar-page" aria-label="项目主页"><span class="icon iconfont icon-home" style=""></span>项目主页<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/slide" class="nav-link sidebar-link sidebar-page" aria-label="幻灯片"><!---->幻灯片<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable active"><span class="icon iconfont icon-creative" style=""></span><a href="/zh/interview/" class="title">面试指南</a><span class="arrow down"></span></button><ul class="sidebar-links"><li><!--[--><a href="/zh/interview/Docker.html" class="nav-link sidebar-link sidebar-page" aria-label="Docker"><span class="icon iconfont icon-lock" style=""></span>Docker<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/Java%E5%9F%BA%E7%A1%80.html" class="nav-link sidebar-link sidebar-page" aria-label="JAVA"><span class="icon iconfont icon-lock" style=""></span>JAVA<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/Java%E5%AE%B9%E5%99%A8.html" class="nav-link sidebar-link sidebar-page" aria-label="Java容器"><span class="icon iconfont icon-lock" style=""></span>Java容器<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a aria-current="page" href="/zh/interview/JUC.html" class="router-link-active router-link-exact-active nav-link active sidebar-link sidebar-page active" aria-label="JUC"><span class="icon iconfont icon-lock" style=""></span>JUC<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_1、并发常见知识点-基础篇" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="1、并发常见知识点（基础篇）"><!---->1、并发常见知识点（基础篇）<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_1、什么是线程和进程" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="1、什么是线程和进程?"><!---->1、什么是线程和进程?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_2、请简要描述线程与进程的关系-区别及优缺点" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、请简要描述线程与进程的关系,区别及优缺点？"><!---->2、请简要描述线程与进程的关系,区别及优缺点？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_3、一句话简单了解堆和方法区" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="3、一句话简单了解堆和方法区"><!---->3、一句话简单了解堆和方法区<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_4、说说并发与并行的区别" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="4、说说并发与并行的区别?"><!---->4、说说并发与并行的区别?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_5、为什么要使用多线程呢" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="5、为什么要使用多线程呢?"><!---->5、为什么要使用多线程呢?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_6、用多线程可能带来什么问题" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="6、用多线程可能带来什么问题?"><!---->6、用多线程可能带来什么问题?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_7、说说线程的生命周期和状态" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="7、说说线程的生命周期和状态?"><!---->7、说说线程的生命周期和状态?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_8、什么是上下文切换" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="8、什么是上下文切换?"><!---->8、什么是上下文切换?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_9、什么是线程死锁-如何避免死锁" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="9、什么是线程死锁?如何避免死锁?"><!---->9、什么是线程死锁?如何避免死锁?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_10、说说-sleep-方法和-wait-方法区别和共同点" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="10、说说 sleep() 方法和 wait() 方法区别和共同点?"><!---->10、说说 sleep() 方法和 wait() 方法区别和共同点?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_11、为什么我们调用-start-方法时会执行-run-方法-为什么我们不能直接调用-run-方法" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="11、为什么我们调用 start() 方法时会执行 run() 方法，为什么我们不能直接调用 run() 方法？"><!---->11、为什么我们调用 start() 方法时会执行 run() 方法，为什么我们不能直接调用 run() 方法？<!----></a><ul class="sidebar-sub-headers"></ul></li></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_2、并发常见知识点-面试题总结-进阶篇" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、并发常见知识点&amp;面试题总结（进阶篇）"><!---->2、并发常见知识点&amp;面试题总结（进阶篇）<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_1、synchronized-关键字" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="1、synchronized 关键字"><!---->1、synchronized 关键字<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_2、volatile-关键字" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、volatile 关键字"><!---->2、volatile 关键字<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_3、threadlocal" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="3、ThreadLocal"><!---->3、ThreadLocal<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_4、线程池" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="4、线程池"><!---->4、线程池<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_5、atomic-原子类" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="5、Atomic 原子类"><!---->5、Atomic 原子类<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_6、aqs" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="6、AQS"><!---->6、AQS<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_7、cas" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="7、CAS"><!---->7、CAS<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_1、什么是cas" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="1、什么是CAS?"><!---->1、什么是CAS?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_2、cas存在的问题" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、CAS存在的问题？"><!---->2、CAS存在的问题？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_2、为什么cas那么快" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、为什么CAS那么快？"><!---->2、为什么CAS那么快？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_3、为什么concurrenthashmap中使用cas-synchronized" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="3、为什么concurrenthashmap中使用cas+synchronized？"><!---->3、为什么concurrenthashmap中使用cas+synchronized？<!----></a><ul class="sidebar-sub-headers"></ul></li></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_3、代码题" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="3、代码题"><!---->3、代码题<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_1、线程通信小例子-交替打印1-100" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="1、线程通信小例子(交替打印1-100)"><!---->1、线程通信小例子(交替打印1-100)<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_2、生产者与消费者" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、生产者与消费者"><!---->2、生产者与消费者<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_3、线程执行顺序怎么控制" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="3、线程执行顺序怎么控制？"><!---->3、线程执行顺序怎么控制？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_4、手写reentrantlock核心" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="4、手写ReentrantLock核心"><!---->4、手写ReentrantLock核心<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/JUC.html#_5、手写线程池" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="5、手写线程池"><!---->5、手写线程池<!----></a><ul class="sidebar-sub-headers"></ul></li></ul></li></ul><!--]--></li><li><!--[--><a href="/zh/interview/JVM.html" class="nav-link sidebar-link sidebar-page" aria-label="JVM"><span class="icon iconfont icon-lock" style=""></span>JVM<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/Linux.html" class="nav-link sidebar-link sidebar-page" aria-label="Linux"><span class="icon iconfont icon-lock" style=""></span>Linux<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/MySQL.html" class="nav-link sidebar-link sidebar-page" aria-label="MySQL"><span class="icon iconfont icon-lock" style=""></span>MySQL<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/NIO%E4%B8%8ENetty.html" class="nav-link sidebar-link sidebar-page" aria-label="Netty"><span class="icon iconfont icon-lock" style=""></span>Netty<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/Redis.html" class="nav-link sidebar-link sidebar-page" aria-label="Redis"><span class="icon iconfont icon-lock" style=""></span>Redis<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html" class="nav-link sidebar-link sidebar-page" aria-label="主流框架"><span class="icon iconfont icon-lock" style=""></span>主流框架<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%8E%E9%AB%98%E6%80%A7%E8%83%BD%E9%AB%98%E5%8F%AF%E7%94%A8.html" class="nav-link sidebar-link sidebar-page" aria-label="分布式"><span class="icon iconfont icon-lock" style=""></span>分布式<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.html" class="nav-link sidebar-link sidebar-page" aria-label="操作系统"><span class="icon iconfont icon-lock" style=""></span>操作系统<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E6%99%BA%E5%8A%9B%E9%A2%98.html" class="nav-link sidebar-link sidebar-page" aria-label="智力题"><span class="icon iconfont icon-lock" style=""></span>智力题<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1.html" class="nav-link sidebar-link sidebar-page" aria-label="系统设计"><span class="icon iconfont icon-lock" style=""></span>系统设计<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.html" class="nav-link sidebar-link sidebar-page" aria-label="计算机网络"><span class="icon iconfont icon-lock" style=""></span>计算机网络<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.html" class="nav-link sidebar-link sidebar-page" aria-label="设计模式"><!---->设计模式<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li></ul></section><!--]--></li><li><!--[--><section class="sidebar-group"><p class="sidebar-heading clickable"><span class="icon iconfont icon-creative" style=""></span><a href="/zh/guide/" class="title">如何使用</a><!----></p><ul class="sidebar-links"><li><!--[--><a href="/zh/guide/page.html" class="nav-link sidebar-link sidebar-page" aria-label="页面配置"><span class="icon iconfont icon-page" style=""></span>页面配置<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/guide/markdown.html" class="nav-link sidebar-link sidebar-page" aria-label="Markdown 展示"><span class="icon iconfont icon-markdown" style=""></span>Markdown 展示<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/guide/disable.html" class="nav-link sidebar-link sidebar-page" aria-label="布局与功能禁用"><span class="icon iconfont icon-config" style=""></span>布局与功能禁用<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/guide/encrypt.html" class="nav-link sidebar-link sidebar-page" aria-label="密码加密的文章"><span class="icon iconfont icon-lock" style=""></span>密码加密的文章<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li></ul></section><!--]--></li><li><!--[--><section class="sidebar-group"><p class="sidebar-heading"><span class="icon iconfont icon-note" style=""></span><span class="title">文章</span><!----></p><ul class="sidebar-links"><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><span class="icon iconfont icon-note" style=""></span><span class="title">文章 1-4</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><p class="sidebar-heading"><span class="icon iconfont icon-note" style=""></span><span class="title">文章 5-12</span><!----></p><ul class="sidebar-links"><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><span class="icon iconfont icon-note" style=""></span><span class="title">文章 5-8</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><p class="sidebar-heading"><span class="icon iconfont icon-note" style=""></span><span class="title">文章 9-12</span><!----></p><ul class="sidebar-links"><li><!--[--><a href="/zh/posts/article9.html" class="nav-link sidebar-link sidebar-page" aria-label="文章 9"><span class="icon iconfont icon-edit" style=""></span>文章 9<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/posts/article10.html" class="nav-link sidebar-link sidebar-page" aria-label="文章 10"><span class="icon iconfont icon-edit" style=""></span>文章 10<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/posts/article11.html" class="nav-link sidebar-link sidebar-page" aria-label="文章 11"><span class="icon iconfont icon-edit" style=""></span>文章 11<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/posts/article12.html" class="nav-link sidebar-link sidebar-page" aria-label="文章 12"><span class="icon iconfont icon-edit" style=""></span>文章 12<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li></ul></section><!--]--></li></ul></section><!--]--></li></ul></section><!--]--></li></ul><!--[--><!----><!--]--></aside><!--[--><main class="page" id="main-content"><!--[--><!----><nav class="breadcrumb disable"></nav><div class="page-title"><h1><span class="icon iconfont icon-lock" style=""></span>JUC</h1><div class="page-info"><span class="author-info" aria-label="作者🖊" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon author-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="author icon"><path d="M649.6 633.6c86.4-48 147.2-144 147.2-249.6 0-160-128-288-288-288s-288 128-288 288c0 108.8 57.6 201.6 147.2 249.6-121.6 48-214.4 153.6-240 288-3.2 9.6 0 19.2 6.4 25.6 3.2 9.6 12.8 12.8 22.4 12.8h704c9.6 0 19.2-3.2 25.6-12.8 6.4-6.4 9.6-16 6.4-25.6-25.6-134.4-121.6-240-243.2-288z"></path></svg><span><a class="author-item" href="https://changlu.blog.csdn.net" target="_blank" rel="noopener noreferrer">长路</a></span><span property="author" content="长路"></span></span><!----><!----><span class="category-info" aria-label="分类🌈" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon category-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="category icon"><path d="M148.41 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H148.41c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.311-40.31zM147.556 553.478H429.73c22.263 0 40.311 18.048 40.311 40.31v282.176c0 22.263-18.048 40.312-40.31 40.312H147.555c-22.263 0-40.311-18.049-40.311-40.312V593.79c0-22.263 18.048-40.311 40.31-40.311zM593.927 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H593.927c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.31-40.31zM730.22 920.502H623.926c-40.925 0-74.22-33.388-74.22-74.425V623.992c0-41.038 33.387-74.424 74.425-74.424h222.085c41.038 0 74.424 33.226 74.424 74.067v114.233c0 10.244-8.304 18.548-18.547 18.548s-18.548-8.304-18.548-18.548V623.635c0-20.388-16.746-36.974-37.33-36.974H624.13c-20.585 0-37.331 16.747-37.331 37.33v222.086c0 20.585 16.654 37.331 37.126 37.331H730.22c10.243 0 18.547 8.304 18.547 18.547 0 10.244-8.304 18.547-18.547 18.547z"></path></svg><ul class="categories-wrapper"><li class="category category8 clickable" role="navigation">面试题</li><meta property="articleSection" content="面试题"></ul></span><span aria-label="标签🏷" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon tag-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="tag icon"><path d="M939.902 458.563L910.17 144.567c-1.507-16.272-14.465-29.13-30.737-30.737L565.438 84.098h-.402c-3.215 0-5.726 1.005-7.634 2.913l-470.39 470.39a10.004 10.004 0 000 14.164l365.423 365.424c1.909 1.908 4.42 2.913 7.132 2.913s5.223-1.005 7.132-2.913l470.39-470.39c2.01-2.11 3.014-5.023 2.813-8.036zm-240.067-72.121c-35.458 0-64.286-28.828-64.286-64.286s28.828-64.285 64.286-64.285 64.286 28.828 64.286 64.285-28.829 64.286-64.286 64.286z"></path></svg><ul class="tags-wrapper"><li class="tag tag7 clickable" role="navigation">JUC</li></ul><meta property="keywords" content="JUC"></span><span class="reading-time-info" aria-label="阅读时间⌛" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon timer-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="timer icon"><path d="M799.387 122.15c4.402-2.978 7.38-7.897 7.38-13.463v-1.165c0-8.933-7.38-16.312-16.312-16.312H256.33c-8.933 0-16.311 7.38-16.311 16.312v1.165c0 5.825 2.977 10.874 7.637 13.592 4.143 194.44 97.22 354.963 220.201 392.763-122.204 37.542-214.893 196.511-220.2 389.397-4.661 5.049-7.638 11.651-7.638 19.03v5.825h566.49v-5.825c0-7.379-2.849-13.981-7.509-18.9-5.049-193.016-97.867-351.985-220.2-389.527 123.24-37.67 216.446-198.453 220.588-392.892zM531.16 450.445v352.632c117.674 1.553 211.787 40.778 211.787 88.676H304.097c0-48.286 95.149-87.382 213.728-88.676V450.445c-93.077-3.107-167.901-81.297-167.901-177.093 0-8.803 6.99-15.793 15.793-15.793 8.803 0 15.794 6.99 15.794 15.793 0 80.261 63.69 145.635 142.01 145.635s142.011-65.374 142.011-145.635c0-8.803 6.99-15.793 15.794-15.793s15.793 6.99 15.793 15.793c0 95.019-73.789 172.82-165.96 177.093z"></path></svg><span>大约 81 分钟</span><meta property="timeRequired" content="PT81M"></span></div><hr></div><div class="toc-place-holder"><aside id="toc"><div class="toc-header">此页内容</div><div class="toc-wrapper"><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_1、并发常见知识点-基础篇" class="router-link-active router-link-exact-active toc-link level2">1、并发常见知识点（基础篇）</a></li><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_1、什么是线程和进程" class="router-link-active router-link-exact-active toc-link level3">1、什么是线程和进程?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_2、请简要描述线程与进程的关系-区别及优缺点" class="router-link-active router-link-exact-active toc-link level3">2、请简要描述线程与进程的关系,区别及优缺点？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_3、一句话简单了解堆和方法区" class="router-link-active router-link-exact-active toc-link level3">3、一句话简单了解堆和方法区</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_4、说说并发与并行的区别" class="router-link-active router-link-exact-active toc-link level3">4、说说并发与并行的区别?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_5、为什么要使用多线程呢" class="router-link-active router-link-exact-active toc-link level3">5、为什么要使用多线程呢?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_6、用多线程可能带来什么问题" class="router-link-active router-link-exact-active toc-link level3">6、用多线程可能带来什么问题?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_7、说说线程的生命周期和状态" class="router-link-active router-link-exact-active toc-link level3">7、说说线程的生命周期和状态?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_8、什么是上下文切换" class="router-link-active router-link-exact-active toc-link level3">8、什么是上下文切换?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_9、什么是线程死锁-如何避免死锁" class="router-link-active router-link-exact-active toc-link level3">9、什么是线程死锁?如何避免死锁?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_10、说说-sleep-方法和-wait-方法区别和共同点" class="router-link-active router-link-exact-active toc-link level3">10、说说 sleep() 方法和 wait() 方法区别和共同点?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_11、为什么我们调用-start-方法时会执行-run-方法-为什么我们不能直接调用-run-方法" class="router-link-active router-link-exact-active toc-link level3">11、为什么我们调用 start() 方法时会执行 run() 方法，为什么我们不能直接调用 run() 方法？</a></li><!----><!--]--></ul><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_2、并发常见知识点-面试题总结-进阶篇" class="router-link-active router-link-exact-active toc-link level2">2、并发常见知识点&amp;面试题总结（进阶篇）</a></li><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_1、synchronized-关键字" class="router-link-active router-link-exact-active toc-link level3">1、synchronized 关键字</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_2、volatile-关键字" class="router-link-active router-link-exact-active toc-link level3">2、volatile 关键字</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_3、threadlocal" class="router-link-active router-link-exact-active toc-link level3">3、ThreadLocal</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_4、线程池" class="router-link-active router-link-exact-active toc-link level3">4、线程池</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_5、atomic-原子类" class="router-link-active router-link-exact-active toc-link level3">5、Atomic 原子类</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_6、aqs" class="router-link-active router-link-exact-active toc-link level3">6、AQS</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_7、cas" class="router-link-active router-link-exact-active toc-link level3">7、CAS</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_1、什么是cas" class="router-link-active router-link-exact-active toc-link level3">1、什么是CAS?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_2、cas存在的问题" class="router-link-active router-link-exact-active toc-link level3">2、CAS存在的问题？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_2、为什么cas那么快" class="router-link-active router-link-exact-active toc-link level3">2、为什么CAS那么快？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_3、为什么concurrenthashmap中使用cas-synchronized" class="router-link-active router-link-exact-active toc-link level3">3、为什么concurrenthashmap中使用cas+synchronized？</a></li><!----><!--]--></ul><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_3、代码题" class="router-link-active router-link-exact-active toc-link level2">3、代码题</a></li><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_1、线程通信小例子-交替打印1-100" class="router-link-active router-link-exact-active toc-link level3">1、线程通信小例子(交替打印1-100)</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_2、生产者与消费者" class="router-link-active router-link-exact-active toc-link level3">2、生产者与消费者</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_3、线程执行顺序怎么控制" class="router-link-active router-link-exact-active toc-link level3">3、线程执行顺序怎么控制？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_4、手写reentrantlock核心" class="router-link-active router-link-exact-active toc-link level3">4、手写ReentrantLock核心</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/JUC.html#_5、手写线程池" class="router-link-active router-link-exact-active toc-link level3">5、手写线程池</a></li><!----><!--]--></ul><!--]--></ul></div></aside></div><!----><div class="theme-hope-content"><h1 id="juc" tabindex="-1"><a class="header-anchor" href="#juc" aria-hidden="true">#</a> JUC</h1><h2 id="_1、并发常见知识点-基础篇" tabindex="-1"><a class="header-anchor" href="#_1、并发常见知识点-基础篇" aria-hidden="true">#</a> 1、并发常见知识点（基础篇）</h2><h3 id="_1、什么是线程和进程" tabindex="-1"><a class="header-anchor" href="#_1、什么是线程和进程" aria-hidden="true">#</a> 1、什么是线程和进程?</h3><h4 id="何为进程" tabindex="-1"><a class="header-anchor" href="#何为进程" aria-hidden="true">#</a> 何为进程?</h4><p>进程是程序的一次执行过程，是<strong>系统运行程序的基本单位</strong>，因此进程是动态的。系统运行一个程序即是一个进程从创建，运行到消亡的过程。</p><p>在 Java 中，当我们启动 main 函数时其实就是启动了一个 JVM 的进程，而 main 函数所在的线程就是这个进程中的一个线程，也称主线程。</p><p>如下图所示，在 windows 中通过查看任务管理器的方式，我们就可以清楚看到 window 当前运行的进程（.exe 文件的运行）。</p><h4 id="何为线程" tabindex="-1"><a class="header-anchor" href="#何为线程" aria-hidden="true">#</a> 何为线程?</h4><p>Java 程序天生就是多线程程序，我们可以通过 JMX 来看一下一个普通的 Java 程序有哪些线程，代码如下。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token doc-comment comment">/**
 * @ClassName Test
 * @Author ChangLu
 * @Date 4/19/2022 10:47 PM
 * @Description 查看一个main方法的各个线程
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MultiThread</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">ConcurrentHashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span><span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> hashmap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ConcurrentHashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取 Java 线程管理 MXBean</span>
        <span class="token class-name">ThreadMXBean</span> threadMXBean <span class="token operator">=</span> <span class="token class-name">ManagementFactory</span><span class="token punctuation">.</span><span class="token function">getThreadMXBean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 不需要获取同步的 monitor 和 synchronizer 信息，仅获取线程和线程堆栈信息</span>
        <span class="token class-name">ThreadInfo</span><span class="token punctuation">[</span><span class="token punctuation">]</span> threadInfos <span class="token operator">=</span> threadMXBean<span class="token punctuation">.</span><span class="token function">dumpAllThreads</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 遍历线程信息，仅打印线程 ID 和线程名称信息</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">ThreadInfo</span> threadInfo <span class="token operator">:</span> threadInfos<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;[&quot;</span> <span class="token operator">+</span> threadInfo<span class="token punctuation">.</span><span class="token function">getThreadId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;] &quot;</span> <span class="token operator">+</span> threadInfo<span class="token punctuation">.</span><span class="token function">getThreadName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>[5] Attach Listener //添加事件
[4] Signal Dispatcher // 分发处理给 JVM 信号的线程
[3] Finalizer //调用对象 finalize 方法的线程
[2] Reference Handler //清除 reference 线程
[1] main //main 线程,程序入口
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>main 线程执行 main 方法即可</p><p>从上面的输出内容可以看出：<strong>一个 Java 程序的运行是 main 线程和多个其他线程同时运行</strong>。</p><h3 id="_2、请简要描述线程与进程的关系-区别及优缺点" tabindex="-1"><a class="header-anchor" href="#_2、请简要描述线程与进程的关系-区别及优缺点" aria-hidden="true">#</a> 2、请简要描述线程与进程的关系,区别及优缺点？</h3><p>多个线程共享进程的堆和方法区 (JDK1.8 之后的元空间)资源，但是每个线程有自己的**程序计数器、虚拟机栈 和 本地方法栈。</p><p><strong>总结</strong>： 线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的，而各线程则不一定，因为同一进程中的线程极有可能会相互影响。线程执行开销小，但不利于资源的管理和保护；而进程正相反。</p><p>为什么<strong>程序计数器</strong>、<strong>虚拟机栈</strong>和<strong>本地方法栈</strong>是线程私有的呢？为什么堆和方法区是线程共享的呢？</p><ul><li>程序计数器私有主要是为了<strong>线程切换后能恢复到正确的执行位置</strong></li><li>虚拟机栈和本地方法栈是线程私有的为了<strong>保证线程中的局部变量不被别的线程访问到</strong>。</li></ul><h3 id="_3、一句话简单了解堆和方法区" tabindex="-1"><a class="header-anchor" href="#_3、一句话简单了解堆和方法区" aria-hidden="true">#</a> 3、一句话简单了解堆和方法区</h3><p>堆和方法区是所有线程共享的资源，其中堆是进程中最大的一块内存，主要用于存放新创建的对象 (几乎所有对象都在这里分配内存)，方法区主要用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。</p><h3 id="_4、说说并发与并行的区别" tabindex="-1"><a class="header-anchor" href="#_4、说说并发与并行的区别" aria-hidden="true">#</a> 4、说说并发与并行的区别?</h3><p><strong>并发</strong>：两个及两个以上的作业在同一 <strong>时间段</strong> 内执行。</p><p><strong>并行</strong>：两个及两个以上的作业在同一 <strong>时刻</strong> 执行。</p><h3 id="_5、为什么要使用多线程呢" tabindex="-1"><a class="header-anchor" href="#_5、为什么要使用多线程呢" aria-hidden="true">#</a> 5、为什么要使用多线程呢?</h3><p>总体：</p><p>1、<strong>从计算机底层来说：</strong> 线程可以比作是轻量级的进程，是程序执行的最小单位,线程间的切换和调度的成本远远小于进程。另外，多核 CPU 时代意味着多个线程可以同时运行，这减少了线程上下文切换的开销。</p><p>2、<strong>从当代互联网发展趋势来说：</strong> 现在的系统动不动就要求百万级甚至千万级的并发量，而多线程并发编程正是开发高并发系统的基础，利用好多线程机制可以大大提高系统整体的并发能力以及性能。</p><p>再深入到计算机底层来探讨：</p><ul><li><strong>单核时代</strong>： 在单核时代多线程主要是为了提高单进程利用 CPU 和 IO 系统的效率。 假设只运行了一个 Java 进程的情况，当我们请求 IO 的时候，如果 Java 进程中只有一个线程，此线程被 IO 阻塞则整个进程被阻塞。CPU 和 IO 设备只有一个在运行，那么可以简单地说系统整体效率只有 50%。当使用多线程的时候，一个线程被 IO 阻塞，其他线程还可以继续使用 CPU。从而提高了 Java 进程利用系统资源的整体效率。</li><li><strong>多核时代</strong>: 多核时代多线程主要是为了提高进程利用多核 CPU 的能力。举个例子：假如我们要计算一个复杂的任务，我们只用一个线程的话，不论系统有几个 CPU 核心，都只会有一个 CPU 核心被利用到。而创建多个线程，这些线程可以被映射到底层多个 CPU 上执行，在任务中的多个线程没有资源竞争的情况下，任务执行的效率会有显著性的提高，约等于（单核时执行时间/CPU 核心数）。</li></ul><h3 id="_6、用多线程可能带来什么问题" tabindex="-1"><a class="header-anchor" href="#_6、用多线程可能带来什么问题" aria-hidden="true">#</a> 6、用多线程可能带来什么问题?</h3><p>并发编程的目的就是为了能提高程序的执行效率提高程序运行速度，但是并发编程并不总是能提高程序运行速度的，而且并发编程可能会遇到很多问题，比如：内存泄漏、死锁、线程不安全等等。</p><h3 id="_7、说说线程的生命周期和状态" tabindex="-1"><a class="header-anchor" href="#_7、说说线程的生命周期和状态" aria-hidden="true">#</a> 7、说说线程的生命周期和状态?</h3><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171439787.png" alt="image-20220617143913717" loading="lazy"></p><p>线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换。Java 线程状态变迁如下图所示：</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171439313.png" alt="image-20220617143935243" loading="lazy"></p><ul><li>订正(来自<a href="https://github.com/Snailclimb/JavaGuide/issues/736" target="_blank" rel="noopener noreferrer">issue736open in new window<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>)：原图中 wait 到 runnable 状态的转换中，<code>join</code>实际上是<code>Thread</code>类的方法，但这里写成了<code>Object</code>。</li></ul><p>由上图可以看出：线程创建之后它将处于 <strong>NEW（新建）</strong> 状态，调用 <code>start()</code> 方法后开始运行，线程这时候处于 <strong>READY（可运行）</strong> 状态。可运行状态的线程获得了 CPU 时间片（timeslice）后就处于 <strong>RUNNING（运行）</strong> 状态。</p><p>当线程执行 <code>wait()</code>方法之后，线程进入 <strong>WAITING（等待）</strong> 状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态，而 <strong>TIMED_WAITING(超时等待)</strong> 状态相当于在等待状态的基础上增加了超时限制，比如通过 <code>sleep（long millis）</code>方法或 <code>wait（long millis）</code>方法可以将 Java 线程置于 TIMED_WAITING 状态。当超时时间到达后 Java 线程将会返回到 RUNNABLE 状态。当线程调用同步方法时，在没有获取到锁的情况下，线程将会进入到 <strong>BLOCKED（阻塞）</strong> 状态。线程在执行 Runnable 的<code>run()</code>方法之后将会进入到 <strong>TERMINATED（终止）</strong> 状态。</p><h3 id="_8、什么是上下文切换" tabindex="-1"><a class="header-anchor" href="#_8、什么是上下文切换" aria-hidden="true">#</a> 8、什么是上下文切换?</h3><p>线程在执行过程中会有自己的运行条件和状态（也称上下文），比如上文所说到过的<strong>程序计数器，栈信息</strong>等。当出现如下情况的时候，线程会从占用 CPU 状态中退出。</p><ul><li>主动让出 CPU，比如调用了 <code>sleep()</code>, <code>wait()</code> 等。</li><li>时间片用完，因为操作系统要防止一个线程或者进程长时间占用CPU导致其他线程或者进程饿死。</li><li>调用了阻塞类型的系统中断，比如请求 IO，线程被阻塞。</li><li>被终止或结束运行</li></ul><p>这其中前三种都会发生线程切换，线程切换意味着需要保存当前线程的上下文，留待线程下次占用 CPU 的时候恢复现场。并加载下一个将要占用 CPU 的线程上下文。这就是所谓的 <strong>上下文切换</strong>。</p><p>上下文切换是现代操作系统的基本功能，因其每次需要保存信息恢复信息，这将会占用 CPU，内存等系统资源进行处理，也就意味着效率会有一定损耗，如果频繁切换就会造成整体效率低下。</p><h3 id="_9、什么是线程死锁-如何避免死锁" tabindex="-1"><a class="header-anchor" href="#_9、什么是线程死锁-如何避免死锁" aria-hidden="true">#</a> 9、什么是线程死锁?如何避免死锁?</h3><h4 id="_1、认识线程死锁" tabindex="-1"><a class="header-anchor" href="#_1、认识线程死锁" aria-hidden="true">#</a> 1、认识线程死锁</h4><p>线程死锁描述的是这样一种情况：多个线程同时被阻塞，它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞，因此程序不可能正常终止。</p><p>如下图所示，线程 A 持有资源 2，线程 B 持有资源 1，他们同时都想申请对方的资源，所以这两个线程就会互相等待而进入死锁状态。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171445506.png" alt="image-20220617144554462" loading="lazy"></p><p>线程 A 通过 <code>synchronized (resource1)</code> 获得 <code>resource1</code> 的监视器锁，然后通过<code>Thread.sleep(1000);</code>让线程 A 休眠 1s 为的是让线程 B 得到执行然后获取到 resource2 的监视器锁。线程 A 和线程 B 休眠结束了都开始企图请求获取对方的资源，然后这两个线程就会陷入互相等待的状态，这也就产生了死锁。</p><p>上面的例子符合产生死锁的四个必要条件：</p><ol><li><strong>互斥条件</strong>：该资源任意一个时刻只由一个线程占用。</li><li><strong>请求与保持条件</strong>：一个线程因请求资源而阻塞时，对已获得的资源保持不放。</li><li><strong>不剥夺条件</strong>:线程已获得的资源在未使用完之前不能被其他线程强行剥夺，只有自己使用完毕后才释放资源。</li><li><strong>循环等待条件</strong>:若干线程之间形成一种头尾相接的循环等待资源关系。</li></ol><h4 id="_2、如何预防和避免线程死锁" tabindex="-1"><a class="header-anchor" href="#_2、如何预防和避免线程死锁" aria-hidden="true">#</a> 2、如何预防和避免线程死锁?</h4><p><strong>如何预防死锁？</strong> 破坏死锁的产生的必要条件即可：</p><ol><li><strong>破坏请求与保持条件</strong> ：一次性申请所有的资源。</li><li><strong>破坏不剥夺条件</strong> ：占用部分资源的线程进一步申请其他资源时，如果申请不到，可以主动释放它占有的资源。</li><li><strong>破坏循环等待条件</strong> ：靠按序申请资源来预防。按某一顺序申请资源，释放资源则反序释放。破坏循环等待条件。</li></ol><h3 id="_10、说说-sleep-方法和-wait-方法区别和共同点" tabindex="-1"><a class="header-anchor" href="#_10、说说-sleep-方法和-wait-方法区别和共同点" aria-hidden="true">#</a> 10、说说 sleep() 方法和 wait() 方法区别和共同点?</h3><p>两者最主要的区别在于：<code>sleep()</code> 方法没有释放锁，而 <code>wait()</code> 方法释放了锁 。</p><p>两者都可以暂停线程的执行。</p><p><code>wait()</code> 通常被用于线程间交互/通信，<code>sleep() </code>通常被用于暂停执行。</p><p><code>wait()</code> 方法被调用后，线程不会自动苏醒，需要别的线程调用同一个对象上的 <code>notify() </code>或者 <code>notifyAll()</code> 方法。<code>sleep() </code>方法执行完成后，线程会自动苏醒。或者可以使用 <code>wait(long timeout)</code> 超时后线程会自动苏醒。</p><h3 id="_11、为什么我们调用-start-方法时会执行-run-方法-为什么我们不能直接调用-run-方法" tabindex="-1"><a class="header-anchor" href="#_11、为什么我们调用-start-方法时会执行-run-方法-为什么我们不能直接调用-run-方法" aria-hidden="true">#</a> 11、为什么我们调用 start() 方法时会执行 run() 方法，为什么我们不能直接调用 run() 方法？</h3><p>这是另一个非常经典的 Java 多线程面试问题，而且在面试中会经常被问到。很简单，但是很多人都会答不上来！</p><p>new 一个 Thread，线程进入了新建状态。调用 <code>start()</code>方法，会启动一个线程并使线程进入了就绪状态，当分配到时间片后就可以开始运行了。 <code>start()</code> 会执行线程的相应准备工作，然后自动执行 <code>run()</code> 方法的内容，这是真正的多线程工作。 但是，直接执行 <code>run()</code> 方法，会把 <code>run()</code> 方法当成一个 main 线程下的普通方法去执行，并不会在某个线程中执行它，所以这并不是多线程工作。</p><p><strong>总结： 调用 <code>start()</code> 方法方可启动线程并使线程进入就绪状态，直接执行 <code>run()</code> 方法的话不会以多线程的方式执行。</strong></p><h2 id="_2、并发常见知识点-面试题总结-进阶篇" tabindex="-1"><a class="header-anchor" href="#_2、并发常见知识点-面试题总结-进阶篇" aria-hidden="true">#</a> 2、并发常见知识点&amp;面试题总结（进阶篇）</h2><h3 id="_1、synchronized-关键字" tabindex="-1"><a class="header-anchor" href="#_1、synchronized-关键字" aria-hidden="true">#</a> 1、synchronized 关键字</h3><h4 id="_1、说一说自己对于-synchronized-关键字的了解" tabindex="-1"><a class="header-anchor" href="#_1、说一说自己对于-synchronized-关键字的了解" aria-hidden="true">#</a> 1、说一说自己对于 synchronized 关键字的了解</h4><p><code>synchronized</code> 关键字解决的是多个线程之间访问资源的同步性，<code>synchronized</code>关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。</p><p>Java 早期版本中，<code>synchronized</code> 属于 <strong>重量级锁</strong>，效率低下：</p><ul><li>监视器锁（monitor）是依赖于底层的操作系统的 <code>Mutex Lock</code> 来实现的，Java 的线程是映射到操作系统的原生线程之上的。如果要挂起或者唤醒一个线程，都需要操作系统帮忙完成，而操作系统实现线程之间的切换时需要从用户态转换到内核态，这个状态之间的转换需要相对比较长的时间，时间成本相对较高。</li></ul><p>Java 6 之后 Java 官方对从 JVM 层面对 <code>synchronized</code> 较大优化，所以现在的 <code>synchronized</code> 锁效率也优化得很不错了。JDK1.6 对锁的实现引入了大量的优化，如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。</p><blockquote><p>核心总结</p></blockquote><p>从版本上来看，jdk1.6默认就是重量级锁，在jdk1.6对锁的获取与释放进行优化，引入了锁升级，添加了偏向锁和轻量级锁(自旋锁)，此时锁的状态就有四个无锁、偏向锁、轻量级锁、重量级锁。</p><p>在synchronized中对象或者class类都可以当做锁，它们使用的锁实际上就是存在对象头中的MarkWord标记字段中。在这个标记字段里就包含有锁的状态，其中锁标志位就表示不同的锁。01表示无锁或偏向锁(它们有对应的一个偏向锁状态，若是0则是无锁，若是1则是偏向锁)，00表示轻量级锁，10表示重量级锁。</p><p>对于重量级锁的解释：每个对象都有一个看不见的锁称为内部锁或者Monitor锁，monitor是线程私有的数据结构，每个线程都有一个可用的monitor record列表，还有一个全局可用列表，每个锁住的的对象都会与一个monitor关联，在monitor中有一个owner字段来存储线程的唯一标识，标识该线程已被占有。Synchronzied就是使用对象中监视器锁monitor来实现的，其底层依赖于操作系统的Mutex Lock互斥锁实现，这个就涉及到用户态与内核态的一个切换，这也是为什么效率低的原因。</p><h4 id="_2、说说自己是怎么使用-synchronized-关键字" tabindex="-1"><a class="header-anchor" href="#_2、说说自己是怎么使用-synchronized-关键字" aria-hidden="true">#</a> 2、说说自己是怎么使用 synchronized 关键字</h4><p><strong>synchronized 关键字最主要的三种使用方式：</strong></p><p><strong>1.修饰实例方法:</strong> 作用于当前对象实例加锁，进入同步代码前要获得 <strong>当前对象实例的锁</strong></p><p><strong>2.修饰静态方法:</strong> 也就是给当前类加锁，会作用于类的所有对象实例 ，进入同步代码前要获得 <strong>当前 class 的锁</strong>。</p><p><strong>3.修饰代码块</strong> ：指定加锁对象，对给定对象/类加锁。</p><h4 id="_3、构造方法可以使用-synchronized-关键字修饰么" tabindex="-1"><a class="header-anchor" href="#_3、构造方法可以使用-synchronized-关键字修饰么" aria-hidden="true">#</a> 3、构造方法可以使用 synchronized 关键字修饰么？</h4><p>先说结论：<strong>构造方法不能使用 synchronized 关键字修饰。</strong></p><p>构造方法本身就属于线程安全的，不存在同步的构造方法一说。</p><h4 id="_4、讲一下-synchronized-关键字的底层原理-修饰语句块、方法情况" tabindex="-1"><a class="header-anchor" href="#_4、讲一下-synchronized-关键字的底层原理-修饰语句块、方法情况" aria-hidden="true">#</a> 4、讲一下 synchronized 关键字的底层原理（修饰语句块、方法情况）</h4><p>synchronized 关键字底层原理属于 JVM 层面。</p><blockquote><p><strong>synchronized 同步语句块的情况</strong></p></blockquote><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SynchronizedDemo</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">method</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;synchronized 代码块&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 JDK 自带的 <code>javap</code> 命令查看 <code>SynchronizedDemo</code> 类的相关字节码信息：首先切换到类的对应目录执行 <code>javac SynchronizedDemo.java</code> 命令生成编译后的 .class 文件，然后执行<code>javap -c -s -v -l SynchronizedDemo.class</code>。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171602553.png" alt="image-20220617160249509" loading="lazy"></p><p><strong><code>synchronized</code> 同步语句块的实现使用的是 <code>monitorenter</code> 和 <code>monitorexit</code> 指令，其中 <code>monitorenter</code> 指令指向同步代码块的开始位置，<code>monitorexit</code> 指令则指明同步代码块的结束位置。</strong></p><p>当执行 <code>monitorenter</code> 指令时，线程试图获取锁也就是获取 <strong>对象监视器 <code>monitor</code></strong> 的持有权。</p><blockquote><p>在 Java 虚拟机(HotSpot)中，Monitor 是基于 C++实现的，由<a href="https://github.com/openjdk-mirror/jdk7u-hotspot/blob/50bdefc3afe944ca74c3093e7448d6b889cd20d1/src/share/vm/runtime/objectMonitor.cpp" target="_blank" rel="noopener noreferrer">ObjectMonitoropen in new window<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>实现的。每个对象中都内置了一个 <code>ObjectMonitor</code>对象。</p><p>另外，<code>wait/notify</code>等方法也依赖于<code>monitor</code>对象，这就是为什么只有在同步的块或者方法中才能调用<code>wait/notify</code>等方法，否则会抛出<code>java.lang.IllegalMonitorStateException</code>的异常的原因。</p></blockquote><p>在执行<code>monitorenter</code>时，会尝试获取对象的锁，如果锁的计数器为 0 则表示锁可以被获取，获取后将锁计数器设为 1 也就是加 1。</p><p>对象锁的的拥有者线程才可以执行 <code>monitorexit</code> 指令来释放锁。在执行 <code>monitorexit</code> 指令后，将锁计数器设为 0，表明锁被释放，其他线程可以尝试获取锁。</p><p>如果获取对象锁失败，那当前线程就要阻塞等待，直到锁被另外一个线程释放为止。</p><blockquote><p><strong>synchronized 修饰方法的的情况</strong></p></blockquote><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SynchronizedDemo2</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">method</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;synchronized 方法&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171606130.png" alt="image-20220617160653083" loading="lazy"></p><p><code>synchronized</code> 修饰的方法并没有 <code>monitorenter</code> 指令和 <code>monitorexit</code> 指令，取得代之的确实是 <code>ACC_SYNCHRONIZED</code> 标识，该标识指明了该方法是一个同步方法。JVM 通过该 <code>ACC_SYNCHRONIZED</code> 访问标志来辨别一个方法是否声明为同步方法，从而执行相应的同步调用。</p><p>如果是实例方法，JVM 会尝试获取实例对象的锁。如果是静态方法，JVM 会尝试获取当前 class 的锁。</p><p><strong>总结内容</strong>：</p><p><code>synchronized</code> 同步语句块的实现使用的是 <code>monitorenter</code> 和 <code>monitorexit</code> 指令，其中 <code>monitorenter</code> 指令指向同步代码块的开始位置，<code>monitorexit</code> 指令则指明同步代码块的结束位置。</p><p><code>synchronized</code> 修饰的方法并没有 <code>monitorenter</code> 指令和 <code>monitorexit</code> 指令，取得代之的确实是 <code>ACC_SYNCHRONIZED</code> 标识，该标识指明了该方法是一个同步方法。</p><p><strong>不过两者的本质都是对对象监视器 monitor 的获取</strong></p><h4 id="_5、说说-jdk1-6-之后的-synchronized-关键字底层做了哪些优化-可以详细介绍一下这些优化吗" tabindex="-1"><a class="header-anchor" href="#_5、说说-jdk1-6-之后的-synchronized-关键字底层做了哪些优化-可以详细介绍一下这些优化吗" aria-hidden="true">#</a> 5、说说 JDK1.6 之后的 synchronized 关键字底层做了哪些优化，可以详细介绍一下这些优化吗</h4><p>JDK1.6 对锁的实现引入了大量的优化，如偏向锁、轻量级锁、自旋锁、适应性自旋锁、锁消除、锁粗化等技术来减少锁操作的开销。</p><p>锁主要存在四种状态，依次是：无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态，他们会随着竞争的激烈而逐渐升级。注意锁可以升级不可降级，这种策略是为了提高获得锁和释放锁的效率。</p><h4 id="_6、谈谈-synchronized-和-reentrantlock-的区别" tabindex="-1"><a class="header-anchor" href="#_6、谈谈-synchronized-和-reentrantlock-的区别" aria-hidden="true">#</a> 6、谈谈 synchronized 和 ReentrantLock 的区别</h4><p>①两者都是可重入锁：<strong>“可重入锁”</strong> 指的是自己可以再次获取自己的内部锁。比如一个线程获得了某个对象的锁，此时这个对象锁还没有释放，当其再次想要获取这个对象的锁的时候还是可以获取的，如果是不可重入锁的话，就会造成死锁。同一个线程每次获取锁，锁的计数器都自增 1，所以要等到锁的计数器下降为 0 时才能释放锁。</p><p>②synchronized 依赖于 JVM 而 ReentrantLock 依赖于 API：<code>synchronized</code> 是依赖于 JVM 实现的，前面我们也讲到了 虚拟机团队在 JDK1.6 为 <code>synchronized</code> 关键字进行了很多优化，但是这些优化都是在虚拟机层面实现的，并没有直接暴露给我们。<code>ReentrantLock</code> 是 JDK 层面实现的（也就是 API 层面，需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成），所以我们可以通过查看它的源代码，来看它是如何实现的。</p><p>③ReentrantLock 比 synchronized 增加了一些高级功能</p><ul><li><strong>等待可中断</strong> : <code>ReentrantLock</code>提供了一种能够中断等待锁的线程的机制，通过 <code>lock.lockInterruptibly()</code> 来实现这个机制。也就是说正在等待的线程可以选择放弃等待，改为处理其他事情。</li><li><strong>可实现公平锁</strong> : <code>ReentrantLock</code>可以指定是公平锁还是非公平锁。而<code>synchronized</code>只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。<code>ReentrantLock</code>默认情况是非公平的，可以通过 <code>ReentrantLock</code>类的<code>ReentrantLock(boolean fair)</code>构造方法来制定是否是公平的。</li><li><strong>可实现选择性通知（锁可以绑定多个条件）</strong>: <code>synchronized</code>关键字与<code>wait()</code>和<code>notify()</code>/<code>notifyAll()</code>方法相结合可以实现等待/通知机制。<code>ReentrantLock</code>类当然也可以实现，但是需要借助于<code>Condition</code>接口与<code>newCondition()</code>方法。</li></ul><p>如果你想使用上述功能，那么选择 ReentrantLock 是一个不错的选择。性能已不是选择标准。</p><h4 id="_7、sychronized锁升级" tabindex="-1"><a class="header-anchor" href="#_7、sychronized锁升级" aria-hidden="true">#</a> 7、Sychronized锁升级</h4><blockquote><p>参考：<a href="https://segmentfault.com/a/1190000022904663" target="_blank" rel="noopener noreferrer">深度分析：锁升级过程和锁状态，看完这篇你就懂了！<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><p>JDK1.6之前：重量级锁。</p><p>1.6之后：对提高锁的获取与释放锁的效率进行优化，引入了偏向锁以及轻量级锁，锁的状态就有了四种（无锁、偏向锁、轻量级锁、重量级锁）。</p></blockquote><p>JDK6以前 synchronized效率低下的原因：最初的实现方式是 “阻塞或唤醒一个Java线程需要操作系统切换CPU状态来完成，这种状态切换需要耗费处理器时间，如果同步代码块中内容过于简单，这种切换的时间可能比用户代码执行的时间还长”。</p><p>JDK6之后：从级别由低到高依次是：无锁、偏向锁，轻量级锁，重量级锁，锁状态只能升级，不能降级。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/3/202204201732813.png" alt="image-20220420173249498" loading="lazy"></p><p>锁的思路与状态：</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/3/202204201733856.png" alt="image-20220420173336802" loading="lazy"></p><p>锁的对比：</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/3/202204201736228.png" alt="image-20220420173614154" loading="lazy"></p><ul><li>偏向锁相当于无锁，加解锁没有额外开销，仅仅只是在线程竞争时，会有额外的锁撤销消耗时间。</li><li>轻量级锁：不会阻塞，其会自旋，会消耗cpu。</li><li>重量级锁：不自旋，而是会进入阻塞。</li></ul><p>synchronized 用的锁是存在<strong>Java对象头</strong>里的，那么什么是对象头呢？</p><p><strong>介绍对象头</strong>：</p><p>以 Hotspot 虚拟机为例，Hopspot 对象头主要包括两部分数据：<code>Mark Word</code>（标记字段） 和 <code>Klass Pointer</code>（类型指针）</p><ul><li>Mark Word：默认存储对象的HashCode，分代年龄和<strong>锁标志位</strong>信息。这些信息都是与对象自身定义无关的数据，所以Mark Word被设计成一个非固定的数据结构以便在极小的空间内存存储尽量多的数据。它会根据对象的状态复用自己的存储空间，也就是说在运行期间Mark Word里存储的数据会随着锁标志位的变化而变化。</li><li>Klass Point：对象指向它的类元数据的指针，虚拟机通过这个指针来确定这个对象是哪个类的实例。</li></ul><p>锁是存在对象头的Mark Word中。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/3/202204201741562.png" alt="image-20220420174139456" loading="lazy"></p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/3/202204201741464.png" alt="image-20220420174151372" loading="lazy"></p><ul><li>无锁 ：对象头开辟 25bit 的空间用来存储对象的 hashcode ，4bit 用于存放对象分代年龄，1bit 用来存放是否偏向锁的标识位，2bit 用来存放锁标识位为01</li><li>偏向锁： 在偏向锁中划分更细，还是开辟 25bit 的空间，其中23bit 用来存放线程ID，2bit 用来存放 Epoch，4bit 存放对象分代年龄，1bit 存放是否偏向锁标识， 0表示无锁，1表示偏向锁，锁的标识位还是01</li><li>轻量级锁：在轻量级锁中直接开辟 30bit 的空间存放指向栈中锁记录的指针，2bit 存放锁的标志位，其标志位为00</li><li>重量级锁： 在重量级锁中和轻量级锁一样，30bit 的空间用来存放指向重量级锁的指针，2bit 存放锁的标识位，为11</li><li>GC标记： 开辟30bit 的内存空间却没有占用，2bit 空间存放锁标志位为11。</li></ul><p>关于内存分配：openJDK中 markOop.hpp中如下【对应目录：hotspot\src\share\vm\oops，<a href="https://github.com/unofficial-openjdk/openjdk/blob/jdk8u/jdk8u/hotspot/src/share/vm/oops/markOop.hpp" target="_blank" rel="noopener noreferrer">github-markoops.hpp<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>】</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span><span class="token operator">:</span>
  <span class="token comment">// Constants</span>
  <span class="token keyword">enum</span> <span class="token punctuation">{</span> age_bits                 <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">,</span>
         lock_bits                <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">,</span>
         biased_lock_bits         <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">,</span>
         max_hash_bits            <span class="token operator">=</span> <span class="token class-name">BitsPerWord</span> <span class="token operator">-</span> age_bits <span class="token operator">-</span> lock_bits <span class="token operator">-</span> biased_lock_bits<span class="token punctuation">,</span>
         hash_bits                <span class="token operator">=</span> max_hash_bits <span class="token operator">&gt;</span> <span class="token number">31</span> <span class="token operator">?</span> <span class="token number">31</span> <span class="token operator">:</span> max_hash_bits<span class="token punctuation">,</span>
         cms_bits                 <span class="token operator">=</span> <span class="token function">LP64_ONLY</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token function">NOT_LP64</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
         epoch_bits               <span class="token operator">=</span> <span class="token number">2</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">//解释：</span>
age_bits： 就是我们说的分代回收的标识，占用<span class="token number">4</span>字节
lock_bits： 是锁的标志位，占用<span class="token number">2</span>个字节
biased_lock_bits： 是是否偏向锁的标识，占用<span class="token number">1</span>个字节
max_hash_bits： 是针对无锁计算的hashcode 占用字节数量，如果是<span class="token number">32</span>位虚拟机，就是 <span class="token number">32</span> <span class="token operator">-</span> <span class="token number">4</span> <span class="token operator">-</span> <span class="token number">2</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token operator">=</span> <span class="token number">25</span> <span class="token keyword">byte</span>，如果是<span class="token number">64</span> 位虚拟机，<span class="token number">64</span> <span class="token operator">-</span> <span class="token number">4</span> <span class="token operator">-</span> <span class="token number">2</span> <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">=</span> <span class="token number">57</span> <span class="token keyword">byte</span>，但是会有 <span class="token number">25</span> 字节未使用，所以<span class="token number">64</span>位的 hashcode 占用 <span class="token number">31</span> <span class="token keyword">byte</span>
hash_bits： 是针对 <span class="token number">64</span> 位虚拟机来说，如果最大字节数大于 <span class="token number">31</span>，则取<span class="token number">31</span>，否则取真实的字节数
cms_bits： 不是<span class="token number">64</span>位虚拟机就占用 <span class="token number">0</span> <span class="token keyword">byte</span>，是<span class="token number">64</span>位就占用 <span class="token number">1</span>byte
epoch_bits： 就是 epoch 所占用的字节大小，<span class="token number">2</span>字节。
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote><p>Monitor</p></blockquote><p>Monitor 可以理解为一个同步工具或一种同步机制，通常被描述为一个对象。每一个 Java 对象就有一把看不见的锁，称为内部锁或者 Monitor 锁。</p><p>Monitor 是线程私有的数据结构，每一个线程都有一个可用 monitor record 列表，同时还有一个全局的可用列表。每一个被锁住的对象都会和一个 monitor 关联，同时 monitor 中有一个 Owner 字段存放拥有该锁的线程的唯一标识，表示该锁被这个线程占用。</p><p>Synchronized是通过对象内部的一个叫做监视器锁（monitor）来实现的，监视器锁本质又是依赖于底层的操作系统的 Mutex Lock（互斥锁）来实现的。而操作系统实现线程之间的切换需要从用户态转换到核心态，这个成本非常高，状态之间的转换需要相对比较长的时间，这就是为什么 Synchronized 效率低的原因。因此，这种依赖于操作系统 <strong>Mutex Lock 所实现的锁我们称之为重量级锁</strong>。</p><ul><li>随着锁的竞争，锁可以从偏向锁升级到轻量级锁，再升级的重量级锁（但是<strong>锁的升级是单向的，也就是说只能从低到高升级，不会出现锁的降级</strong>）。JDK 1.6中默认是开启偏向锁和轻量级锁的，我们也可以通过-XX:-UseBiasedLocking=false来禁用偏向锁。</li></ul><blockquote><p>各个锁介绍</p></blockquote><p>无锁：无锁是指没有对资源进行锁定，所有的线程都能访问并修改同一个资源，但同时只有一个线程能修改成功。</p><ul><li>无锁的特点是修改操作会在循环内进行，线程会不断的尝试修改共享资源。如果没有冲突就修改成功并退出，否则就会继续循环尝试。如果有多个线程修改同一个值，必定会有一个线程能修改成功，而其他修改失败的线程会不断重试直到修改成功。</li></ul><p>偏向锁：偏向于第一个获得它的线程”的锁，</p><ul><li>过程：初次执行到synchronized代码块的时候，<strong>锁对象变成偏向锁（通过CAS修改对象头里的锁标志位）</strong>，当第二次到达同步代码块时，线程会判断此时持有锁的线程是否就是自己（持有锁的线程ID也在对象头里），如果是则正常往下执行。由于之前没有释放锁，这里也就不需要重新加锁。如果自始至终使用锁的线程只有一个，很明显偏向锁几乎没有额外开销，性能极高。</li><li>何时释放锁：偏向锁只有遇到其他线程尝试竞争偏向锁时，持有偏向锁的线程才会释放锁，<strong>线程是不会主动释放偏向锁的</strong>。</li><li>关于撤销锁：偏向锁的撤销，需要等待全局安全点，即在某个时间点上没有字节码正在执行时，它会先暂停拥有偏向锁的线程，然后判断锁对象是否处于被锁定状态。如果线程不处于活动状态，则将对象头设置成无锁状态，并撤销偏向锁，恢复到无锁（标志位为01）或轻量级锁（标志位为00）的状态。</li><li>实际开销：偏向锁只需要在置换对象头的 ThreadID 的时候依赖一次 CAS 原子指令即可。</li></ul><p>轻量级锁：当锁是偏向锁的时候，却被另外的线程所访问，此时偏向锁就会升级为轻量级锁，其他线程会通过自旋的形式尝试获取锁，线程不会阻塞，从而提高性能。</p><ul><li>获取的两种方式：①当关闭偏向锁功能时。②由于多个线程竞争偏向锁导致偏向锁升级为轻量级锁。一旦有第二个线程加入锁竞争，偏向锁就升级为轻量级锁（自旋锁）</li><li>竞争过程：在轻量级锁状态下继续锁竞争，没有抢到锁的线程将自旋，即不停地循环判断锁是否能够被成功获取。获取锁的操作，其实就是通过CAS修改对象头里的锁标志位。①先比较当前锁标志位是否为“释放”。如果是则将其设置为“锁定”，比较并设置是原子性发生的。②然后线程将当前锁的持有者信息修改为自己。</li><li>对于自旋的一个思考：长时间的自旋操作是非常消耗资源的，一个线程持有锁，其他线程就只能在原地空耗CPU，执行不了任何有效的任务，这种现象叫做忙等（busy-waiting）。如果多个线程用一个锁，但是没有发生锁竞争，或者发生了很轻微的锁竞争，那么synchronized就用轻量级锁，允许短时间的忙等现象。这是一种折衷的想法，短时间的忙等，换取线程在用户态和内核态之间切换的开销。</li></ul><p>重量级锁：个计数器记录自旋次数，默认允许循环10次(轻量级锁竞争)，可以通过虚拟机参数更改。</p><ul><li>升级过程：如果锁竞争情况严重，某个达到最大自旋次数的线程，会将轻量级锁升级为重量级锁（依然是CAS修改锁标志位，但不修改持有锁的线程ID）。当后续线程尝试获取锁时，发现被占用的锁是重量级锁，则直接将自己挂起（而不是忙等），等待将来被唤醒。</li><li>效果：<strong>重量级锁是指当有一个线程获取锁之后，其余所有等待获取该锁的线程都会处于阻塞状态</strong>。</li><li>简而言之使用重量级锁时：所有的控制权都交给了操作系统，由操作系统来负责线程间的调度和线程的状态变更。而这样会出现频繁地对线程运行状态的切换，线程的挂起和唤醒，从而消耗大量的系统资源。</li></ul><blockquote><p>锁竞争</p></blockquote><p>这里要明确一下什么是锁竞争：如果多个线程轮流获取一个锁，但是每次获取锁的时候都很顺利，没有发生阻塞，那么就不存在锁竞争。<strong>只有当某线程尝试获取锁的时候，发现该锁已经被占用，只能等待其释放，这才发生了锁竞争。</strong></p><h4 id="_8、synchronized锁升级降级问题" tabindex="-1"><a class="header-anchor" href="#_8、synchronized锁升级降级问题" aria-hidden="true">#</a> 8、synchronized锁升级降级问题</h4><blockquote><p><strong>大致的过程梳理</strong>：无锁-》重量级锁</p></blockquote><p>锁对象刚刚创建，没有线程来访问它默认就是无锁状态。【对象头的Mark word（锁标志位-01 是否偏向-0）】</p><p>线程A来访问这个锁对象，此时就会偏向这个线程，线程A首先会去检查Mark word若是无锁状态，那么该对象锁就会升级为<strong>偏向锁</strong>【对象头的Mark word（锁标志位-01 是否偏向-1 ，线程ID-线程A的ID）】</p><ul><li>升级操作：就是使用cas来进行修改是否偏向为1以及指向线程A的id。</li><li>升级之后若是一直是一个线程来进行访问就不会有什么开锁解锁开销，一直偏向这这个线程来执行下去。</li><li>注意：在获取锁的同时在锁的线程上就会分配上一个lock record也就是锁记录，这个锁记录就是对象头中的Mark Word。</li></ul><p>(1)线程A执行同步完成之后，线程B来获取对象锁，此时会检查Mark word，由于其中线程ID指向线程A，那么则表示有不同线程来竞争，该偏向锁会升级为轻量级锁，之后由B来获得。【这个升级的操作就是使用cas来进行修改标志头】</p><p>(2)线程A执行同步过程中，线程B来竞争对象锁，由于对象头Mark word指向线程A，此时就会执行锁升级，升级过程中线程A是暂停的，此时线程A帧栈中就会创建一个lock record并拷贝当前Mark word【锁标志位-00，其他位-线程A锁记录的指针】，待升级完成之后JVM唤醒线程A，线程A持有这个轻量级锁【锁标志位-00，其他位-线程A锁记录的指针】，继续执行同步代码块。</p><ul><li>若是执行结束没有线程来竞争就会正常释放轻量级锁，将原本保存的偏向锁Mark word设置替换到对象头中。</li><li>若是执行过程中，有线程B来竞争，那么线程B首先也会在帧栈建立锁记录，拷贝锁对象目前的Mark word【锁标志位-00，其他位-线程A锁记录的指针】，线程B会尝试使用CAS来去将Mark word的指针改为B，若是成功说明线程A刚刚释放。 <ul><li>若是失败，那么就会使用自旋的方式来进行等待轻量级锁线程释放锁，在自旋了一定时间之后若是依旧失败，此时线程B会阻塞，等待释放锁后唤醒，此时轻量级锁就会膨胀为重量级锁【锁标志位-10，其他位-重量级锁monitor的指针】。</li><li>此时线程A执行完了，就会尝试将它原本线程中的lock record替换回锁，由于当前对象头中对象头不再是原来轻量级锁指针，那么cas就会失败，在释放轻量级锁CAS操作替换失败之后，释放锁的同时需要唤醒被挂起的线程B，线程B被唤醒，获取重量级monitor。</li></ul></li></ul><blockquote><p>分析：<a href="https://blog.csdn.net/qq_41489540/article/details/113475507" target="_blank" rel="noopener noreferrer">03.synchronized锁升级降级问题<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>、<a href="https://www.jianshu.com/p/fd780ef7a2e8" target="_blank" rel="noopener noreferrer">Lock Record--锁记录<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>、<a href="https://blog.csdn.net/yunqiinsight/article/details/118416218?spm=1001.2101.3001.6650.1&amp;utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.pc_relevant_default&amp;depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.pc_relevant_default&amp;utm_relevant_index=2" target="_blank" rel="noopener noreferrer">阿里云—谈谈JVM内部锁升级过程<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p></blockquote><p>所谓锁的升级、降级，就是 JVM 优化 synchronized 运行的机制，当 JVM 检测到不同的竞争状况时，会自动切换到适合的锁实现，这种切换就是锁的升级、降级。</p><p>如果有另外的线程试图锁定某个已经被偏斜过的对象，JVM 就需要撤销（revoke）偏斜锁，并切换到轻量级锁实现。轻量级锁依赖 CAS 操作 Mark Word 来试图获取锁，如果重试成功，就使用普通的轻量级锁；否则，进一步升级为重量级锁。</p><p>我注意到有的观点认为 Java 不会进行锁降级。实际上据我所知，锁降级确实是会发生的，当 JVM 进入安全点（SafePoint）的时候，会检查是否有闲置的 Monitor，然后试图进行降级。</p><p>详细过程：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code>如下分析，从一个没有线程访问的锁逐渐升级到重量级锁的过程：

<span class="token number">1</span>）一个锁对象刚刚开始创建的时候，没有任何线程来访问它，此时线程状态为无锁状态。<span class="token class-name">Mark</span> word（锁标志位<span class="token operator">-</span><span class="token number">01</span> 是否偏向<span class="token operator">-</span><span class="token number">0</span>）
<span class="token number">2</span>）当线程<span class="token class-name">A</span>来访问这个对象锁时，它会偏向这个线程<span class="token class-name">A</span>。线程<span class="token class-name">A</span>检查<span class="token class-name">Mark</span> word（锁标志位<span class="token operator">-</span><span class="token number">01</span> 是否偏向<span class="token operator">-</span><span class="token number">0</span>）为无锁状态。此时，有线程访问锁了，无锁升级为偏向锁，<span class="token class-name">Mark</span> word（锁标志位<span class="token operator">-</span><span class="token number">01</span>，是否偏向<span class="token operator">-</span><span class="token number">1</span>，线程ID<span class="token operator">-</span>线程<span class="token class-name">A</span>的ID）
<span class="token number">3</span>）当线程<span class="token class-name">A</span>执行完同步块时，不会主动释放偏向锁。持有偏向锁的线程执行完同步代码后不会主动释放偏向锁，而是等待其他线程来竞争才会释放锁。<span class="token class-name">Mark</span> word不变（锁标志位<span class="token operator">-</span><span class="token number">01</span>，是否偏向<span class="token operator">-</span><span class="token number">1</span>，线程ID<span class="token operator">-</span>线程<span class="token class-name">A</span>的ID）
<span class="token number">4</span>）当线程<span class="token class-name">A</span>再次获取这个对象锁时，检查<span class="token class-name">Mark</span> word（锁标志位<span class="token operator">-</span><span class="token number">01</span>，是否偏向<span class="token operator">-</span><span class="token number">1</span>，线程ID<span class="token operator">-</span>线程<span class="token class-name">A</span>的ID），偏向锁且偏向线程<span class="token class-name">A</span>，可以直接执行同步代码。这样偏向锁保证了总是同一个线程多次获取锁的情况下，每次只需要检查标志位就行，效率很高。
<span class="token number">5</span>）当线程<span class="token class-name">A</span>执行完同步块之后，线程<span class="token class-name">B</span>获取这个对象锁 检查<span class="token class-name">Mark</span> word（锁标志位<span class="token operator">-</span><span class="token number">01</span>，是否偏向<span class="token operator">-</span><span class="token number">1</span>，线程ID<span class="token operator">-</span>线程<span class="token class-name">A</span>的ID），偏向锁且偏向线程<span class="token class-name">A</span>。有不同的线程获取锁对象，偏向锁升级为轻量级锁，并由线程<span class="token class-name">B</span>获取该锁。
<span class="token number">6</span>）当线程<span class="token class-name">A</span>正在执行同步块时，也就是正持有偏向锁时，线程<span class="token class-name">B</span>获取来这个对象锁。
检查<span class="token class-name">Mark</span> word（锁标志位<span class="token operator">-</span><span class="token number">01</span>，是否偏向<span class="token operator">-</span><span class="token number">1</span>，线程ID<span class="token operator">-</span>线程<span class="token class-name">A</span>的ID），偏向锁且偏向线程<span class="token class-name">A</span>。

<span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span>线程<span class="token class-name">A</span>撤销偏向锁<span class="token operator">:</span>

<span class="token number">1.</span> 等到全局安全点执行撤销偏向锁，暂停持有偏向锁的线程<span class="token class-name">A</span>并检查程<span class="token class-name">A</span>的状态；
<span class="token number">2.</span> 如果线程<span class="token class-name">A</span>不处于活动状态或者已经退出同步代码块，则将对象锁设置为无锁状态，然后再升级为轻量级锁。由线程<span class="token class-name">B</span>获取轻量级锁。
<span class="token number">3.</span> 如果线程<span class="token class-name">A</span>还在执行同步代码块，也就是线程<span class="token class-name">A</span>还需要这个对象锁，则偏向锁膨胀为轻量级锁。
    
<span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span>线程<span class="token class-name">A</span>膨胀为轻量级锁过程：
    
<span class="token number">4.</span> 在升级为轻量级锁之前，持有偏向锁的线程（线程<span class="token class-name">A</span>）是暂停的
<span class="token number">5.</span> 线程<span class="token class-name">A</span>栈帧中创建一个名为锁记录的空间（<span class="token class-name">Lock</span> <span class="token class-name">Record</span>）
<span class="token number">6.</span> 锁对象头中的<span class="token class-name">Mark</span> <span class="token class-name">Word</span>拷贝到线程<span class="token class-name">A</span>的锁记录中
<span class="token number">7.</span> <span class="token class-name">Mark</span> <span class="token class-name">Word</span>的锁标志位变为<span class="token number">00</span>，指向锁记录的指针指向线程<span class="token class-name">A</span>的锁记录地址，<span class="token class-name">Mark</span> word（锁标志位<span class="token operator">-</span><span class="token number">00</span>，其他位<span class="token operator">-</span>线程<span class="token class-name">A</span>锁记录的指针）
<span class="token number">8.</span> 当原持有偏向锁的线程（线程<span class="token class-name">A</span>）获取轻量级锁后，JVM唤醒线程<span class="token class-name">A</span>，线程<span class="token class-name">A</span>执行同步代码块
<span class="token number">7</span>）线程<span class="token class-name">A</span>持有轻量级锁，线程<span class="token class-name">A</span>执行完同步块代码之后，一直没有线程来竞争对象锁，正常释放轻量级锁。释放轻量级锁操作：CAS操作将线程<span class="token class-name">A</span>的锁记录（<span class="token class-name">Lock</span> <span class="token class-name">Record</span>）中的<span class="token class-name">Mark</span> <span class="token class-name">Word</span>替换回锁对象头中。
<span class="token number">8</span>）线程<span class="token class-name">A</span>持有轻量级锁，执行同步块代码过程中，线程<span class="token class-name">B</span>来竞争对象锁。
<span class="token class-name">Mark</span> word（锁标志位<span class="token operator">-</span><span class="token number">00</span>，其他位<span class="token operator">-</span>线程<span class="token class-name">A</span>锁记录的指针）

<span class="token number">9.</span> 线程<span class="token class-name">B</span>会先在栈帧中建立锁记录，存储锁对象目前的<span class="token class-name">Mark</span> <span class="token class-name">Word</span>的拷贝
<span class="token number">10.</span> 线程<span class="token class-name">B</span>通过CAS操作尝试将锁对象的<span class="token class-name">Mark</span> <span class="token class-name">Word</span>的指针指向线程<span class="token class-name">B</span>的<span class="token class-name">Lock</span> <span class="token class-name">Record</span>，如果成功，说明线程<span class="token class-name">A</span>刚刚释放锁，线程<span class="token class-name">B</span>竞争到锁，则执行同步代码块。
<span class="token number">11.</span> 因为线程<span class="token class-name">A</span>一直持有锁，大部分情况下CAS是会失败的。CAS失败之后，线程<span class="token class-name">B</span>尝试使用自旋的方式来等待持有轻量级锁的线程释放锁。
<span class="token number">12.</span> 线程<span class="token class-name">B</span>不会一直自旋下去，如果自旋了一定次数后还是失败，线程<span class="token class-name">B</span>会被阻塞，等待释放锁后唤醒。此时轻量级锁就会膨胀为重量级锁。<span class="token class-name">Mark</span> word（锁标志位<span class="token operator">-</span><span class="token number">10</span>，其他位<span class="token operator">-</span>重量级锁monitor的指针）
<span class="token number">13.</span> 线程<span class="token class-name">A</span>执行完同步块代码之后，执行释放锁操作，CAS 操作将线程<span class="token class-name">A</span>的锁记录（<span class="token class-name">Lock</span> <span class="token class-name">Record</span>）中的<span class="token class-name">Mark</span> <span class="token class-name">Word</span> 替换回锁对象对象头中，因为对象头中已经不是原来的轻量级锁的指针了，而是重量级锁的指针，所以CAS操作会失败。
<span class="token number">14.</span> 释放轻量级锁CAS操作替换失败之后，需要在释放锁的同时需要唤醒被挂起的线程<span class="token class-name">B</span>。线程<span class="token class-name">B</span>被唤醒，获取重量级锁monitor
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="_2、volatile-关键字" tabindex="-1"><a class="header-anchor" href="#_2、volatile-关键字" aria-hidden="true">#</a> 2、volatile 关键字</h3><blockquote><p><a href="https://www.nowcoder.com/feed/main/detail/95f5d2c64c384eeb91f1fb3c1c75fe77" target="_blank" rel="noopener noreferrer">面试官问dcl为什么用volatile 我回答是为了禁止指令重排序,防止返回没有完成初始化的singleton对象 他一直说不对 还一直问我 我真的难受啊<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p></blockquote><p><strong>问题：dcl为什么用volatile？</strong></p><ul><li>①保证可见性，多线程情况下，初始化立即能被看见。②防止指令重排。</li></ul><p>volatile 的作用确实不是禁止指令重排序（虽然网上大都是这么笼统的说的） 之所以多线程会获取到未完全初始化完成的单例对象，是因为new关键字在字节码中是分三步来执行的，正是这三步的乱序造成了线程不安全的问题。<strong>volatile真正的作用是在这三步字节码前后加上内存屏障</strong>（而不是禁止重排），从而防止对象在未初始化完成就被获取。</p><p>当线程a正在new单例对象的时候，可以简单理解为，此时加上内存屏障后，另一个线程b就只能在三步执行完后才能获取到这个对象，也就不会受到乱不乱序的影响了。</p><ul><li>java1.5之前的内存模型是有缺陷的，1.5之后更新了新的内存模型，并完善了volatile 的语义。根据happens-before 原则，任何针对volatile 的store，都不能reorder到之前的store/load之前，这也就是内存屏障的作用。所以从这个角度，是可以说禁止了重排序。我开头说的并非禁止重排序，可能有些歧义，是指并不能禁止new关键字的三步字节码的重排序，这里明确一下。</li></ul><p>volitale底层就是用的<strong>内存屏障禁止指令重排序的</strong> 其中又分<strong>内存的读写屏障 写屏障禁止把写屏障之前的指令优化到写屏障之后</strong> 读屏障禁止把读屏障之后的指令优化到读屏障之前。</p><h4 id="_1、cpu-缓存模型" tabindex="-1"><a class="header-anchor" href="#_1、cpu-缓存模型" aria-hidden="true">#</a> 1、CPU 缓存模型</h4><p>类比我们开发网站后台系统使用的缓存（比如 Redis）是为了解决程序处理速度和访问常规关系型数据库速度不对等的问题。 <strong>CPU 缓存则是为了解决 CPU 处理速度和内存处理速度不对等的问题。</strong></p><p>我们甚至可以把 <strong>内存可以看作外存的高速缓存</strong>，程序运行的时候我们把外存的数据复制到内存，由于内存的处理速度远远高于外存，这样提高了处理速度。</p><p>总结：<strong>CPU Cache 缓存的是内存数据用于解决 CPU 处理速度和内存不匹配的问题，内存缓存的是硬盘数据用于解决硬盘访问速度过慢的问题。</strong></p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171629276.png" alt="image-20220617162935103" loading="lazy"></p><p><strong>CPU Cache 的工作方式：</strong></p><p>先复制一份数据到 CPU Cache 中，当 CPU 需要用到的时候就可以直接从 CPU Cache 中读取数据，当运算完成后，再将运算得到的数据写回 Main Memory 中。但是，这样存在 <strong>内存缓存不一致性的问题</strong> ！比如我执行一个 i++操作的话，如果两个线程同时执行的话，假设两个线程从 CPU Cache 中读取的 i=1，两个线程做了 1++运算完之后再写回 Main Memory 之后 i=2，而正确结果应该是 i=3。</p><p><strong>CPU 为了解决内存缓存不一致性问题可以通过制定缓存一致协议或者其他手段来解决。</strong></p><h4 id="_2、讲一下-jmm-java-内存模型" tabindex="-1"><a class="header-anchor" href="#_2、讲一下-jmm-java-内存模型" aria-hidden="true">#</a> 2、讲一下 JMM(Java 内存模型)</h4><p>Java 内存模型抽象了线程和主内存之间的关系，就比如说线程之间的共享变量必须存储在主内存中。Java 内存模型主要目的是为了屏蔽系统和硬件的差异，避免一套代码在不同的平台下产生的效果不一致。</p><p>在 JDK1.2 之前，Java 的内存模型实现总是从<strong>主存</strong>（即共享内存）读取变量，是不需要进行特别的注意的。而在当前的 Java 内存模型下，线程可以把变量保存<strong>本地内存</strong>（比如机器的寄存器）中，而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值，而另外一个线程还继续使用它在寄存器中的变量值的拷贝，造成<strong>数据的不一致</strong>。</p><ul><li><strong>主内存</strong> ：所有线程创建的实例对象都存放在主内存中，不管该实例对象是成员变量还是方法中的本地变量(也称局部变量)</li><li><strong>本地内存</strong> ：每个线程都有一个私有的本地内存来存储共享变量的副本，并且，每个线程只能访问自己的本地内存，无法访问其他线程的本地内存。本地内存是 JMM 抽象出来的一个概念，存储了主内存中的共享变量副本。</li></ul><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171632833.png" alt="image-20220617163216640" loading="lazy"></p><p>要解决这个问题，就需要把变量声明为 <strong><code>volatile</code></strong> ，这就指示 JVM，这个变量是共享且不稳定的，每次使用它都到主存中进行读取。</p><p>所以，<strong><code>volatile</code> 关键字 除了防止 JVM 的指令重排 ，还有一个重要的作用就是保证变量的可见性。</strong></p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171632539.png" alt="image-20220617163232341" loading="lazy"></p><h4 id="_3、并发编程的三个重要特性" tabindex="-1"><a class="header-anchor" href="#_3、并发编程的三个重要特性" aria-hidden="true">#</a> 3、并发编程的三个重要特性</h4><ol><li><strong>原子性</strong> : 一次操作或者多次操作，要么所有的操作全部都得到执行并且不会受到任何因素的干扰而中断，要么都不执行。<code>synchronized</code> 可以保证代码片段的原子性。</li><li><strong>可见性</strong> ：当一个线程对共享变量进行了修改，那么另外的线程都是立即可以看到修改后的最新值。<code>volatile</code> 关键字可以保证共享变量的可见性。</li><li><strong>有序性</strong> ：代码在执行的过程中的先后顺序，Java 在编译器以及运行期间的优化，代码的执行顺序未必就是编写代码时候的顺序。<code>volatile</code> 关键字可以禁止指令进行重排序优化。</li></ol><h4 id="_4、说说-synchronized-关键字和-volatile-关键字的区别" tabindex="-1"><a class="header-anchor" href="#_4、说说-synchronized-关键字和-volatile-关键字的区别" aria-hidden="true">#</a> 4、说说 synchronized 关键字和 volatile 关键字的区别</h4><p><code>synchronized</code> 关键字和 <code>volatile</code> 关键字是两个互补的存在，而不是对立的存在！</p><ul><li><strong><code>volatile</code> 关键字</strong>是线程同步的<strong>轻量级实现</strong>，所以 <strong><code>volatile </code>性能肯定比<code>synchronized</code>关键字要好</strong> 。但是 <strong><code>volatile</code> 关键字只能用于变量而 <code>synchronized</code> 关键字可以修饰方法以及代码块</strong> 。</li><li><strong><code>volatile</code> 关键字能保证数据的可见性，但不能保证数据的原子性。<code>synchronized</code> 关键字两者都能保证。</strong></li><li><strong><code>volatile</code>关键字主要用于解决变量在多个线程之间的可见性，而 <code>synchronized</code> 关键字解决的是多个线程之间访问资源的同步性。</strong></li></ul><h3 id="_3、threadlocal" tabindex="-1"><a class="header-anchor" href="#_3、threadlocal" aria-hidden="true">#</a> 3、ThreadLocal</h3><h4 id="_1、threadlocal-简介" tabindex="-1"><a class="header-anchor" href="#_1、threadlocal-简介" aria-hidden="true">#</a> 1、ThreadLocal 简介</h4><p>创建的变量是可以被任何一个线程访问并修改的。<strong>如果想实现每一个线程都有自己的专属本地变量该如何解决呢？</strong> JDK 中提供的<code>ThreadLocal</code>类正是为了解决这样的问题。 <strong><code>ThreadLocal</code>类主要解决的就是让每个线程绑定自己的值，可以将<code>ThreadLocal</code>类形象的比喻成存放数据的盒子，盒子中可以存储每个线程的私有数据。</strong></p><p><strong>如果你创建了一个<code>ThreadLocal</code>变量，那么访问这个变量的每个线程都会有这个变量的本地副本，这也是<code>ThreadLocal</code>变量名的由来。他们可以使用 <code>get（）</code> 和 <code>set（）</code> 方法来获取默认值或将其值更改为当前线程所存的副本的值，从而避免了线程安全问题。</strong></p><h4 id="_2、threadlocal-原理" tabindex="-1"><a class="header-anchor" href="#_2、threadlocal-原理" aria-hidden="true">#</a> 2、ThreadLocal 原理</h4><p>从 <code>Thread</code>类源代码入手：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Thread</span> <span class="token keyword">implements</span> <span class="token class-name">Runnable</span> <span class="token punctuation">{</span>
    <span class="token comment">//......</span>
    <span class="token comment">//与此线程有关的ThreadLocal值。由ThreadLocal类维护</span>
    <span class="token class-name">ThreadLocal<span class="token punctuation">.</span>ThreadLocalMap</span> threadLocals <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

    <span class="token comment">//与此线程有关的InheritableThreadLocal值。由InheritableThreadLocal类维护</span>
    <span class="token class-name">ThreadLocal<span class="token punctuation">.</span>ThreadLocalMap</span> inheritableThreadLocals <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token comment">//......</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>从上面<code>Thread</code>类 源代码可以看出<code>Thread</code> 类中有一个 <code>threadLocals</code> 和 一个 <code>inheritableThreadLocals</code> 变量，它们都是 <code>ThreadLocalMap</code> 类型的变量,我们可以把 <code>ThreadLocalMap</code> 理解为<code>ThreadLocal</code> 类实现的定制化的 <code>HashMap</code>。默认情况下这两个变量都是 null，只有当前线程调用 <code>ThreadLocal</code> 类的 <code>set</code>或<code>get</code>方法时才创建它们，实际上调用这两个方法的时候，我们调用的是<code>ThreadLocalMap</code>类对应的 <code>get()</code>、<code>set()</code>方法。</p><p>通过上面这些内容，我们足以通过猜测得出结论：<strong>最终的变量是放在了当前线程的 <code>ThreadLocalMap</code> 中，并不是存在 <code>ThreadLocal</code> 上，<code>ThreadLocal</code> 可以理解为只是<code>ThreadLocalMap</code>的封装，传递了变量值。</strong> <code>ThrealLocal</code> 类中可以通过<code>Thread.currentThread()</code>获取到当前线程对象后，直接通过<code>getMap(Thread t)</code>可以访问到该线程的<code>ThreadLocalMap</code>对象。</p><p><strong>每个<code>Thread</code>中都具备一个<code>ThreadLocalMap</code>，而<code>ThreadLocalMap</code>可以存储以<code>ThreadLocal</code>为 key ，Object 对象为 value 的键值对。</strong></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">ThreadLocalMap</span><span class="token punctuation">(</span><span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> firstKey<span class="token punctuation">,</span> <span class="token class-name">Object</span> firstValue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//......</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>比如我们在同一个线程中声明了两个 <code>ThreadLocal</code> 对象的话， <code>Thread</code>内部都是使用仅有的那个<code>ThreadLocalMap</code> 存放数据的，<code>ThreadLocalMap</code>的 key 就是 <code>ThreadLocal</code>对象，value 就是 <code>ThreadLocal</code> 对象调用<code>set</code>方法设置的值。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171653961.png" alt="image-20220617165326835" loading="lazy"></p><p><code>ThreadLocalMap</code>是<code>ThreadLocal</code>的静态内部类。</p><h4 id="_3、threadlocal-内存泄露问题" tabindex="-1"><a class="header-anchor" href="#_3、threadlocal-内存泄露问题" aria-hidden="true">#</a> 3、ThreadLocal 内存泄露问题</h4><p><code>ThreadLocalMap</code> 中使用的 key 为 <code>ThreadLocal</code> 的弱引用,而 value 是强引用。所以，如果 <code>ThreadLocal</code> 没有被外部强引用的情况下，在垃圾回收的时候，key 会被清理掉，而 value 不会被清理掉。这样一来，<code>ThreadLocalMap</code> 中就会出现 key 为 null 的 Entry。假如我们不做任何措施的话，value 永远无法被 GC 回收，这个时候就可能会产生内存泄露。ThreadLocalMap 实现中已经考虑了这种情况，在调用 <code>set()</code>、<code>get()</code>、<code>remove()</code> 方法的时候，会清理掉 key 为 null 的记录。使用完 <code>ThreadLocal</code>方法后 最好手动调用<code>remove()</code>方法</p><p><strong>弱引用介绍：</strong></p><blockquote><p>如果一个对象只具有弱引用，那就类似于<strong>可有可无的生活用品</strong>。弱引用与软引用的区别在于：只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中，一旦发现了只具有弱引用的对象，不管当前内存空间足够与否，都会回收它的内存。不过，由于垃圾回收器是一个优先级很低的线程， 因此不一定会很快发现那些只具有弱引用的对象。</p><p>弱引用可以和一个引用队列（ReferenceQueue）联合使用，如果弱引用所引用的对象被垃圾回收，Java 虚拟机就会把这个弱引用加入到与之关联的引用队列中。</p></blockquote><h3 id="_4、线程池" tabindex="-1"><a class="header-anchor" href="#_4、线程池" aria-hidden="true">#</a> 4、线程池</h3><h4 id="_1、为什么要用线程池" tabindex="-1"><a class="header-anchor" href="#_1、为什么要用线程池" aria-hidden="true">#</a> 1、为什么要用线程池？</h4><blockquote><p>池化技术想必大家已经屡见不鲜了，线程池、数据库连接池、Http 连接池等等都是对这个思想的应用。池化技术的思想主要是为了减少每次获取资源的消耗，提高对资源的利用率。</p></blockquote><p><strong>线程池</strong>提供了一种限制和管理资源（包括执行一个任务）的方式。 每个<strong>线程池</strong>还维护一些基本统计信息，例如已完成任务的数量。</p><p><strong>好处</strong>：</p><ul><li><strong>降低资源消耗</strong>。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。</li><li><strong>提高响应速度</strong>。当任务到达时，任务可以不需要等到线程创建就能立即执行。</li><li><strong>提高线程的可管理性</strong>。线程是稀缺资源，如果无限制的创建，不仅会消耗系统资源，还会降低系统的稳定性，使用线程池可以进行统一的分配，调优和监控。</li></ul><h4 id="_2、实现-runnable-接口和-callable-接口的区别" tabindex="-1"><a class="header-anchor" href="#_2、实现-runnable-接口和-callable-接口的区别" aria-hidden="true">#</a> 2、实现 Runnable 接口和 Callable 接口的区别</h4><p>Runnable没有返回值，Callable有返回值。</p><p><code>Runnable</code>自 Java 1.0 以来一直存在，但<code>Callable</code>仅在 Java 1.5 中引入,目的就是为了来处理<code>Runnable</code>不支持的用例。<strong><code>Runnable</code> 接口</strong> 不会返回结果或抛出检查异常，但是 <strong><code>Callable</code> 接口</strong> 可以。所以，如果任务不需要返回结果或抛出异常推荐使用 <strong><code>Runnable</code> 接口</strong> ，这样代码看起来会更加简洁。</p><h4 id="_3、执行-execute-方法和-submit-方法的区别是什么呢" tabindex="-1"><a class="header-anchor" href="#_3、执行-execute-方法和-submit-方法的区别是什么呢" aria-hidden="true">#</a> 3、执行 execute()方法和 submit()方法的区别是什么呢？</h4><ol><li><strong><code>execute()</code>方法用于提交不需要返回值的任务，所以无法判断任务是否被线程池执行成功与否；</strong></li><li><strong><code>submit()</code>方法用于提交需要返回值的任务。线程池会返回一个 <code>Future</code> 类型的对象，通过这个 <code>Future</code> 对象可以判断任务是否执行成功</strong>，并且可以通过 <code>Future</code> 的 <code>get()</code>方法来获取返回值，<code>get()</code>方法会阻塞当前线程直到任务完成，而使用 <code>get(long timeout，TimeUnit unit)</code>方法则会阻塞当前线程一段时间后立即返回，这时候有可能任务没有执行完。</li></ol><p>我们以 <strong><code>AbstractExecutorService</code> 接口</strong> 中的一个 <code>submit</code> 方法为例子来看看源代码：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token class-name">Future</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> <span class="token function">submit</span><span class="token punctuation">(</span><span class="token class-name">Runnable</span> task<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>task <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">NullPointerException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">RunnableFuture</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Void</span><span class="token punctuation">&gt;</span></span> ftask <span class="token operator">=</span> <span class="token function">newTaskFor</span><span class="token punctuation">(</span>task<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">execute</span><span class="token punctuation">(</span>ftask<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> ftask<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面方法调用的 <code>newTaskFor</code> 方法返回了一个 <code>FutureTask</code> 对象。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">RunnableFuture</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token function">newTaskFor</span><span class="token punctuation">(</span><span class="token class-name">Runnable</span> runnable<span class="token punctuation">,</span> <span class="token class-name">T</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">FutureTask</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>runnable<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>我们再来看看<code>execute()</code>方法：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token class-name">Runnable</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="_4、如何创建线程池" tabindex="-1"><a class="header-anchor" href="#_4、如何创建线程池" aria-hidden="true">#</a> 4、如何创建线程池</h4><p>强制线程池不允许使用 Executors 去创建，而是通过 ThreadPoolExecutor 的方式，这样的处理方式让写的同学更加明确线程池的运行规则，规避资源耗尽的风险。</p><p><strong>方式一：通过构造方法实现</strong></p><p><strong>方式二：通过 Executor 框架的工具类 Executors 来实现</strong></p><p>我们可以创建三种类型的 ThreadPoolExecutor：</p><ul><li><strong>FixedThreadPool</strong> ： 该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时，线程池中若有空闲线程，则立即执行。若没有，则新的任务会被暂存在一个任务队列中，待有线程空闲时，便处理在任务队列中的任务。</li><li><strong>SingleThreadExecutor：</strong> 方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线程池，任务会被保存在一个任务队列中，待线程空闲，按先入先出的顺序执行队列中的任务。</li><li><strong>CachedThreadPool：</strong> 该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定，但若有空闲线程可以复用，则会优先使用可复用的线程。若所有线程均在工作，又有新的任务提交，则会创建新的线程处理任务。所有线程在当前任务执行完毕后，将返回线程池进行复用。</li></ul><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171707275.png" alt="image-20220617170722175" loading="lazy"></p><h4 id="_5、threadpoolexecutor-类分析" tabindex="-1"><a class="header-anchor" href="#_5、threadpoolexecutor-类分析" aria-hidden="true">#</a> 5、ThreadPoolExecutor 类分析</h4><p><code>ThreadPoolExecutor</code> 类中提供的四个构造方法。我们来看最长的那个，其余三个都是在这个构造方法的基础上产生（其他几个构造方法说白点都是给定某些默认参数的构造方法比如默认制定拒绝策略是什么），这里就不贴代码讲了，比较简单。</p><p><strong><code>ThreadPoolExecutor</code> 3 个最重要的参数：</strong></p><ul><li><strong><code>corePoolSize</code> :</strong> 核心线程数定义了最小可以同时运行的线程数量。</li><li><strong><code>maximumPoolSize</code> :</strong> 当队列中存放的任务达到队列容量的时候，当前可以同时运行的线程数量变为最大线程数。</li><li><strong><code>workQueue</code>:</strong> 当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数，如果达到的话，新任务就会被存放在队列中。</li></ul><p><code>ThreadPoolExecutor</code>其他常见参数:</p><ol><li><strong><code>keepAliveTime</code></strong>:当线程池中的线程数量大于 <code>corePoolSize</code> 的时候，如果这时没有新的任务提交，核心线程外的线程不会立即销毁，而是会等待，直到等待的时间超过了 <code>keepAliveTime</code>才会被回收销毁；</li><li><strong><code>unit</code></strong> : <code>keepAliveTime</code> 参数的时间单位。</li><li><strong><code>threadFactory</code></strong> :executor 创建新线程的时候会用到。</li><li><strong><code>handler</code></strong> :饱和策略。关于饱和策略下面单独介绍一下。</li></ol><p><strong><code>ThreadPoolExecutor</code> 饱和策略定义:</strong></p><p>如果当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时，<code>ThreadPoolTaskExecutor</code> 定义一些策略:</p><ul><li><strong><code>ThreadPoolExecutor.AbortPolicy</code>：</strong> 抛出 <code>RejectedExecutionException</code>来拒绝新任务的处理。</li><li><strong><code>ThreadPoolExecutor.CallerRunsPolicy</code>：</strong> 调用执行自己的线程运行任务，也就是直接在调用<code>execute</code>方法的线程中运行(<code>run</code>)被拒绝的任务，如果执行程序已关闭，则会丢弃该任务。因此这种策略会降低对于新任务提交速度，影响程序的整体性能。如果您的应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话，你可以选择这个策略。</li><li><strong><code>ThreadPoolExecutor.DiscardPolicy</code>：</strong> 不处理新任务，直接丢弃掉。</li><li><strong><code>ThreadPoolExecutor.DiscardOldestPolicy</code>：</strong> 此策略将丢弃最早的未处理的任务请求。</li></ul><p>举个例子： Spring 通过 <code>ThreadPoolTaskExecutor</code> 或者我们直接通过 <code>ThreadPoolExecutor</code> 的构造函数创建线程池的时候，当我们不指定 <code>RejectedExecutionHandler</code> 饱和策略的话来配置线程池的时候默认使用的是 <code>ThreadPoolExecutor.AbortPolicy</code>。在默认情况下，<code>ThreadPoolExecutor</code> 将抛出 <code>RejectedExecutionException</code> 来拒绝新来的任务 ，这代表你将丢失对这个任务的处理。 对于可伸缩的应用程序，建议使用 <code>ThreadPoolExecutor.CallerRunsPolicy</code>。当最大池被填满时，此策略为我们提供可伸缩队列。（这个直接查看 <code>ThreadPoolExecutor</code> 的构造函数源码就可以看出，比较简单的原因，这里就不贴代码了）</p><blockquote><p>自定义线程</p></blockquote><p>1、<code>corePoolSize</code>: 核心线程数为 5。</p><p>2、<code>maximumPoolSize</code> ：最大线程数 10</p><p>3、<code>keepAliveTime</code> : 等待时间为 1L。</p><p>4、<code>unit</code>: 等待时间的单位为 TimeUnit.SECONDS。</p><p>5、<code>workQueue</code>：任务队列为 <code>ArrayBlockingQueue</code>，并且容量为 100;</p><p>6、<code>handler</code>:饱和策略为 <code>CallerRunsPolicy</code>。</p><h4 id="_6、线程池的组成-组成、构造、拒绝策略、工作过程" tabindex="-1"><a class="header-anchor" href="#_6、线程池的组成-组成、构造、拒绝策略、工作过程" aria-hidden="true">#</a> 6、线程池的组成（组成、构造、拒绝策略、工作过程）</h4><p>一般的线程池主要分为以下 4 个组成部分：</p><p>1、线程池管理器：用于创建并管理线程池。</p><p>2、工作线程：线程池中的线程。</p><p>3、任务接口：每个任务必须实现的接口，用于工作线程调度其运行。</p><p>4、任务队列：用于存放待处理的任务，提供一种缓冲机制。</p><p>Java 中的线程池是通过 Executor 框架实现的，该框架中用到了 Executor，Executors，ExecutorService，ThreadPoolExecutor ，Callable 和 Future、FutureTask 这几个类。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206261422629.png" alt="image-20220626142239501" loading="lazy"></p><p>ThreadPoolExecutor 的构造方法如下：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token class-name">ThreadPoolExecutor</span><span class="token punctuation">(</span><span class="token keyword">int</span> corePoolSize<span class="token punctuation">,</span><span class="token keyword">int</span> maximumPoolSize<span class="token punctuation">,</span> <span class="token keyword">long</span> keepAliveTime<span class="token punctuation">,</span><span class="token class-name">TimeUnit</span> unit<span class="token punctuation">,</span> <span class="token class-name">BlockingQueue</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Runnable</span><span class="token punctuation">&gt;</span></span> workQueue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">(</span>corePoolSize<span class="token punctuation">,</span> maximumPoolSize<span class="token punctuation">,</span> keepAliveTime<span class="token punctuation">,</span> unit<span class="token punctuation">,</span> workQueue<span class="token punctuation">,</span>
    <span class="token class-name">Executors</span><span class="token punctuation">.</span><span class="token function">defaultThreadFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> defaultHandler<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>1、corePoolSize：指定了线程池中的线程数量。 2、maximumPoolSize：指定了线程池中的最大线程数量。 3、keepAliveTime：当前线程池数量超过 corePoolSize 时，多余的空闲线程的存活时间，即多 次时间内会被销毁。 4、unit：keepAliveTime 的单位。 5、workQueue：任务队列，被提交但尚未被执行的任务。 6、threadFactory：线程工厂，用于创建线程，一般用默认的即可。 7、handler：拒绝策略，当任务太多来不及处理，如何拒绝任务。</p><blockquote><p>拒绝策略</p></blockquote><p>线程池中的线程已经用完了，无法继续为新任务服务，同时，等待队列也已经排满了，再也塞不下新任务了。这时候我们就需要拒绝策略机制合理的处理这个问题。JDK 内置的拒绝策略如下：</p><ol><li><code>AbortPolicy </code>： 直接抛出异常，阻止系统正常运行。</li><li><code>CallerRunsPolicy</code> ： 只要线程池未关闭，该策略直接在调用者线程中，运行当前被丢弃的 任务。显然这样做不会真的丢弃任务，但是，任务提交线程的性能极有可能会急剧下降。</li><li><code>DiscardOldestPolicy</code> ： 丢弃最老的一个请求，也就是即将被执行的一个任务，并尝试再 次提交当前任务。</li><li><code>DiscardPolicy</code> ： 该策略默默地丢弃无法处理的任务，不予任何处理。如果允许任务丢 失，这是最好的一种方案。 以上内置拒绝策略均实现了 <code>RejectedExecutionHandler </code>接口，若以上策略仍无法满足实际 需要，完全可以自己扩展 <code>RejectedExecutionHandler </code>接口。</li></ol><blockquote><p>工作过程</p></blockquote><p>1、线程池刚创建时，里面没有一个线程。任务队列是作为参数传进来的。不过，就算队列里面有任务，线程池也不会马上执行它们。</p><p>2、当调用 execute() 方法添加一个任务时，线程池会做如下判断：</p><p>a)如果正在运行的线程数量小于 corePoolSize，那么马上创建线程运行这个任务；</p><p>b) 如果正在运行的线程数量大于或等于 corePoolSize，那么将这个任务放入队列；</p><p>c)如果这时候队列满了，而且正在运行的线程数量小于 maximumPoolSize，那么还是要创建非核心线程立刻运行这个任务；</p><p>d) 如果队列满了，而且正在运行的线程数量大于或等于 maximumPoolSize，那么线程池 会抛出异常 RejectExecutionException。</p><p>3、当一个线程完成任务时，它会从队列中取下一个任务来执行。</p><p>4、当一个线程无事可做，超过一定的时间（keepAliveTime）时，线程池会判断，如果当前运行的线程数大于 corePoolSize，那么这个线程就被停掉。所以线程池的所有任务完成后，它最终会收缩到 corePoolSize 的大小。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206261431691.png" alt="image-20220626143118574" loading="lazy"></p><h4 id="_7、线程池原理分析" tabindex="-1"><a class="header-anchor" href="#_7、线程池原理分析" aria-hidden="true">#</a> 7、线程池原理分析</h4><p>线程池做的工作<strong>主要是控制运行的线程的数量</strong>，处理过程中将任务放入队列，然后在线程创建后启动这些任务，如果线程数量超过了最大数量超出数量的线程排队等候，等其它线程执行完毕，再从队列中取出任务来执行。</p><p>主要特点为：线程复用；控制最大并发数；管理线程。</p><ul><li>线程复用：每一个 Thread 的类都有一个 start 方法。 当调用 start 启动线程时 Java 虚拟机会调用该类的 run方法。 那么该类的 run() 方法中就是调用了 Runnable 对象的 run() 方法。 <strong>我们可以继承重写Thread 类，在其 start 方法中添加不断循环调用传递过来的 Runnable 对象</strong>。 这就是<strong>线程池的实现原理</strong>。循环方法中不断获取 Runnable 是用 Queue 实现的，在获取下一个 Runnable 之前可以是阻塞的。</li></ul><p>在 4.6 节中的 Demo 中我们使用 <code>executor.execute(worker)</code>来提交一个任务到线程池中去，这个方法非常重要，下面我们来看看它的源码：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 存放线程池的运行状态 (runState) 和线程池内有效线程的数量 (workerCount)</span>
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">AtomicInteger</span> ctl <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AtomicInteger</span><span class="token punctuation">(</span><span class="token function">ctlOf</span><span class="token punctuation">(</span>RUNNING<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">workerCountOf</span><span class="token punctuation">(</span><span class="token keyword">int</span> c<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> c <span class="token operator">&amp;</span> CAPACITY<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">BlockingQueue</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Runnable</span><span class="token punctuation">&gt;</span></span> workQueue<span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token class-name">Runnable</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 如果任务为null，则抛出异常。</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>command <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">NullPointerException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// ctl 中保存的线程池当前的一些状态信息</span>
    <span class="token keyword">int</span> c <span class="token operator">=</span> ctl<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">//  下面会涉及到 3 步 操作</span>
    <span class="token comment">// 1.首先判断当前线程池中执行的任务数量是否小于 corePoolSize</span>
    <span class="token comment">// 如果小于的话，通过addWorker(command, true)新建一个线程，并将任务(command)添加到该线程中；然后，启动该线程从而执行任务。</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">workerCountOf</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span> <span class="token operator">&lt;</span> corePoolSize<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">addWorker</span><span class="token punctuation">(</span>command<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        c <span class="token operator">=</span> ctl<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 2.如果当前执行的任务数量大于等于 corePoolSize 的时候就会走到这里</span>
    <span class="token comment">// 通过 isRunning 方法判断线程池状态，线程池处于 RUNNING 状态并且队列可以加入任务，该任务才会被加入进去</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isRunning</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> workQueue<span class="token punctuation">.</span><span class="token function">offer</span><span class="token punctuation">(</span>command<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> recheck <span class="token operator">=</span> ctl<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 再次获取线程池状态，如果线程池状态不是 RUNNING 状态就需要从任务队列中移除任务，并尝试判断线程是否全部执行完毕。同时执行拒绝策略。</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">isRunning</span><span class="token punctuation">(</span>recheck<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">remove</span><span class="token punctuation">(</span>command<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token function">reject</span><span class="token punctuation">(</span>command<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 如果当前线程池为空就新创建一个线程并执行。</span>
        <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">workerCountOf</span><span class="token punctuation">(</span>recheck<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
            <span class="token function">addWorker</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">//3. 通过addWorker(command, false)新建一个线程，并将任务(command)添加到该线程中；然后，启动该线程从而执行任务。</span>
    <span class="token comment">//如果addWorker(command, false)执行失败，则通过reject()执行相应的拒绝策略的内容。</span>
    <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">addWorker</span><span class="token punctuation">(</span>command<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token function">reject</span><span class="token punctuation">(</span>command<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171734238.png" alt="image-20220617173420176" loading="lazy"></p><h3 id="_5、atomic-原子类" tabindex="-1"><a class="header-anchor" href="#_5、atomic-原子类" aria-hidden="true">#</a> 5、Atomic 原子类</h3><h4 id="_1、介绍一下-atomic-原子类" tabindex="-1"><a class="header-anchor" href="#_1、介绍一下-atomic-原子类" aria-hidden="true">#</a> 1、介绍一下 Atomic 原子类</h4><p><code>Atomic</code> 翻译成中文是原子的意思。在化学上，我们知道原子是构成一般物质的最小单位，在化学反应中是不可分割的。在我们这里 Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候，一个操作一旦开始，就不会被其他线程干扰。</p><p>所以，所谓原子类说简单点就是具有原子/原子操作特征的类。</p><p>并发包 <code>java.util.concurrent</code> 的原子类都存放在<code>java.util.concurrent.atomic</code>下,如下图所示。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171735525.png" alt="image-20220617173536464" loading="lazy"></p><h4 id="_2、juc-包中的原子类是哪-4-类" tabindex="-1"><a class="header-anchor" href="#_2、juc-包中的原子类是哪-4-类" aria-hidden="true">#</a> 2、JUC 包中的原子类是哪 4 类?</h4><p><strong>基本类型</strong></p><p>使用原子的方式更新基本类型</p><ul><li><code>AtomicInteger</code>：整型原子类</li><li><code>AtomicLong</code>：长整型原子类</li><li><code>AtomicBoolean</code>：布尔型原子类</li></ul><p><strong>数组类型</strong></p><p>使用原子的方式更新数组里的某个元素</p><ul><li><code>AtomicIntegerArray</code>：整型数组原子类</li><li><code>AtomicLongArray</code>：长整型数组原子类</li><li><code>AtomicReferenceArray</code>：引用类型数组原子类</li></ul><p><strong>引用类型</strong></p><ul><li><code>AtomicReference</code>：引用类型原子类</li><li><code>AtomicStampedReference</code>：原子更新带有版本号的引用类型。该类将整数值与引用关联起来，可用于解决原子的更新数据和数据的版本号，可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。</li><li><code>AtomicMarkableReference</code> ：原子更新带有标记位的引用类型</li></ul><p><strong>对象的属性修改类型</strong></p><ul><li><code>AtomicIntegerFieldUpdater</code>：原子更新整型字段的更新器</li><li><code>AtomicLongFieldUpdater</code>：原子更新长整型字段的更新器</li><li><code>AtomicReferenceFieldUpdater</code>：原子更新引用类型字段的更新器</li></ul><h4 id="_3、讲讲-atomicinteger-的使用" tabindex="-1"><a class="header-anchor" href="#_3、讲讲-atomicinteger-的使用" aria-hidden="true">#</a> 3、讲讲 AtomicInteger 的使用</h4><p><strong>AtomicInteger 类常用方法</strong></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//获取当前的值</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token function">getAndSet</span><span class="token punctuation">(</span><span class="token keyword">int</span> newValue<span class="token punctuation">)</span><span class="token comment">//获取当前的值，并设置新的值</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token function">getAndIncrement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">//获取当前的值，并自增</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token function">getAndDecrement</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//获取当前的值，并自减</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token function">getAndAdd</span><span class="token punctuation">(</span><span class="token keyword">int</span> delta<span class="token punctuation">)</span> <span class="token comment">//获取当前的值，并加上预期的值</span>
<span class="token keyword">boolean</span> <span class="token function">compareAndSet</span><span class="token punctuation">(</span><span class="token keyword">int</span> expect<span class="token punctuation">,</span> <span class="token keyword">int</span> update<span class="token punctuation">)</span> <span class="token comment">//如果输入的数值等于预期值，则以原子方式将该值设置为输入值（update）</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">lazySet</span><span class="token punctuation">(</span><span class="token keyword">int</span> newValue<span class="token punctuation">)</span><span class="token comment">//最终设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>AtomicInteger 类的使用示例</strong></p><p>使用 AtomicInteger 之后，不用对 increment() 方法加锁也可以保证线程安全。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">class</span> <span class="token class-name">AtomicIntegerTest</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">AtomicInteger</span> count <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AtomicInteger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//使用AtomicInteger之后，不需要对该方法加锁，也可以实现线程安全。</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">increment</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        count<span class="token punctuation">.</span><span class="token function">incrementAndGet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">getCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> count<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="_4、能不能给我简单介绍一下-atomicinteger-类的原理" tabindex="-1"><a class="header-anchor" href="#_4、能不能给我简单介绍一下-atomicinteger-类的原理" aria-hidden="true">#</a> 4、能不能给我简单介绍一下 AtomicInteger 类的原理</h4><p>AtomicInteger 线程安全原理简单分析</p><p>AtomicInteger 类的部分源码：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// setup to use Unsafe.compareAndSwapInt for updates（更新操作时提供“比较并替换”的作用）</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Unsafe</span> unsafe <span class="token operator">=</span> <span class="token class-name">Unsafe</span><span class="token punctuation">.</span><span class="token function">getUnsafe</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">long</span> valueOffset<span class="token punctuation">;</span>

<span class="token keyword">static</span> <span class="token punctuation">{</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        valueOffset <span class="token operator">=</span> unsafe<span class="token punctuation">.</span>objectFieldOffset
            <span class="token punctuation">(</span><span class="token class-name">AtomicInteger</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getDeclaredField</span><span class="token punctuation">(</span><span class="token string">&quot;value&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span>ex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">int</span> value<span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>AtomicInteger 类主要利用 CAS (compare and swap) + volatile 和 native 方法来保证原子操作，从而避免 synchronized 的高开销，执行效率大为提升。</p><p>CAS 的原理是拿期望的值和原本的一个值作比较，如果相同则更新成新的值。UnSafe 类的 objectFieldOffset() 方法是一个本地方法，这个方法是用来拿到“原来的值”的内存地址，返回值是 valueOffset。另外 value 是一个 volatile 变量，在内存中可见，因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。</p><h3 id="_6、aqs" tabindex="-1"><a class="header-anchor" href="#_6、aqs" aria-hidden="true">#</a> 6、AQS</h3><h4 id="_1、aqs-介绍" tabindex="-1"><a class="header-anchor" href="#_1、aqs-介绍" aria-hidden="true">#</a> 1、AQS 介绍</h4><p>AQS 的全称为（<code>AbstractQueuedSynchronizer</code>），这个类在<code>java.util.concurrent.locks</code>包下面。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206171828902.png" alt="image-20220617182853837" loading="lazy"></p><p>AQS 是一个用来构建锁和同步器的框架，使用 AQS 能简单且高效地构造出大量应用广泛的同步器，比如我们提到的 <code>ReentrantLock</code>，<code>Semaphore</code>，其他的诸如 <code>ReentrantReadWriteLock</code>，<code>SynchronousQueue</code>，<code>FutureTask</code> 等等皆是基于 AQS 的。当然，我们自己也能利用 AQS 非常轻松容易地构造出符合我们自己需求的同步器。</p><h4 id="_2、aqs-原理分析" tabindex="-1"><a class="header-anchor" href="#_2、aqs-原理分析" aria-hidden="true">#</a> 2、AQS 原理分析</h4><p>AQS 核心思想是：如果被请求的共享资源空闲，则将当前请求资源的线程设置为有效的工作线程，并且将共享资源设置为锁定状态。如果被请求的共享资源被占用，那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制，这个机制 <strong>AQS 是使用CLH 队列锁实现的，即将暂时获取不到锁的线程加入到队列中</strong>。</p><ul><li>CLH(Craig,Landin and Hagersten)队列是一个虚拟的双向队列（虚拟的双向队列即不存在队列实例，仅存在结点之间的关联关系）。AQS 是将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点（Node）来实现锁的分配。</li></ul><p><code>AQS</code>，<code>AbstractQueuedSynchronizer</code>，<strong>抽象队列同步器</strong>，定义了一套多线程访问共享资源的同步器框架，许多并发工具的实现都依赖于它，如常用的ReentrantLock/Semaphore/CountDownLatch。</p><p><code>AQS</code>使用一个volatile的int类型的成员变量state来表示同步状态，通过CAS修改同步状态的值。当线程调用 lock 方法时 ，如果 state=0，说明没有任何线程占有共享资源的锁，可以获得锁并将 state=1。如果 state=1，则说明有线程目前正在使用共享变量，其他线程必须加入同步队列进行等待。</p><p>AQS 使用一个 int 成员变量来<strong>表示同步状态</strong>，通过内置的 FIFO 队列来完成获取资源线程的排队工作。AQS 使用 CAS 对该同步状态进行原子操作实现对其值的修改。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">int</span> state<span class="token punctuation">;</span><span class="token comment">//共享变量，使用volatile修饰保证线程可见性</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>同步器依赖内部的同步队列（一个FIFO双向队列）来完成同步状态的管理，当前线程获取同步状态失败时，同步器会将当前线程以及等待状态（独占或共享 ）构造成为一个节点（<code>Node</code>）并将其加入同步队列并进行自旋，当同步状态释放时，会把首节中的后继节点对应的线程唤醒，使其再次尝试获取同步状态。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206271544960.png" alt="image-20220627154440854" loading="lazy"></p><p>状态信息通过 protected 类型的 getState，setState，compareAndSetState 进行操作</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">//返回同步状态的当前值</span>
<span class="token keyword">protected</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token function">getState</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> state<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//设置同步状态的值</span>
<span class="token keyword">protected</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">setState</span><span class="token punctuation">(</span><span class="token keyword">int</span> newState<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    state <span class="token operator">=</span> newState<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//原子地（CAS操作）将同步状态值设置为给定值update如果当前同步状态的值等于expect（期望值）</span>
<span class="token keyword">protected</span> <span class="token keyword">final</span> <span class="token keyword">boolean</span> <span class="token function">compareAndSetState</span><span class="token punctuation">(</span><span class="token keyword">int</span> expect<span class="token punctuation">,</span> <span class="token keyword">int</span> update<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> unsafe<span class="token punctuation">.</span><span class="token function">compareAndSwapInt</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> stateOffset<span class="token punctuation">,</span> expect<span class="token punctuation">,</span> update<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="_3、aqs-对资源的共享方式" tabindex="-1"><a class="header-anchor" href="#_3、aqs-对资源的共享方式" aria-hidden="true">#</a> 3、AQS 对资源的共享方式</h4><p><strong>AQS 定义两种资源共享方式</strong></p><ul><li>Exclusive（独占）：只有一个线程能执行，如ReentrantLock又可分为公平锁和非公平锁： <ul><li>公平锁：按照线程在队列中的排队顺序，先到者先拿到锁</li><li>非公平锁：当线程要获取锁时，无视队列顺序直接去抢锁，谁抢到就是谁的</li></ul></li><li><strong>Share</strong>（共享）：多个线程可同时执行，如<code> CountDownLatch</code>、<code>Semaphore</code>、 <code>CyclicBarrier</code>、<code>ReadWriteLock</code> 我们都会在后面讲到。</li></ul><p><code>ReentrantReadWriteLock</code> 可以看成是组合式，因为 <code>ReentrantReadWriteLock</code> 也就是读写锁允许多个线程同时对某一资源进行读。</p><p>不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实现共享资源 state 的获取与释放方式即可，至于具体线程等待队列的维护（如获取资源失败入队/唤醒出队等），AQS 已经在顶层实现好了。</p><h4 id="_4、aqs-底层使用了模板方法模式" tabindex="-1"><a class="header-anchor" href="#_4、aqs-底层使用了模板方法模式" aria-hidden="true">#</a> 4、AQS 底层使用了模板方法模式</h4><p>同步器的设计是基于模板方法模式的，如果需要自定义同步器一般的方式是这样（模板方法模式很经典的一个应用）：</p><ol><li>使用者继承 <code>AbstractQueuedSynchronizer</code> 并重写指定的方法。（这些重写方法很简单，无非是对于共享资源 state 的获取和释放）</li><li>将 AQS 组合在自定义同步组件的实现中，并调用其模板方法，而这些模板方法会调用使用者重写的方法。</li></ol><p>这和我们以往通过实现接口的方式有很大区别，这是模板方法模式很经典的一个运用</p><p><strong>AQS 使用了模板方法模式，自定义同步器时需要重写下面几个 AQS 提供的钩子方法：</strong></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">boolean</span> <span class="token function">tryAcquire</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token comment">//独占方式。尝试获取资源，成功则返回true，失败则返回false。</span>
<span class="token keyword">protected</span> <span class="token keyword">boolean</span> <span class="token function">tryRelease</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token comment">//独占方式。尝试释放资源，成功则返回true，失败则返回false。</span>
<span class="token keyword">protected</span> <span class="token keyword">int</span> <span class="token function">tryAcquireShared</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token comment">//共享方式。尝试获取资源。负数表示失败；0表示成功，但没有剩余可用资源；正数表示成功，且有剩余资源。</span>
<span class="token keyword">protected</span> <span class="token keyword">boolean</span> <span class="token function">tryReleaseShared</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token comment">//共享方式。尝试释放资源，成功则返回true，失败则返回false。</span>
<span class="token keyword">protected</span> <span class="token keyword">boolean</span> <span class="token function">isHeldExclusively</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">//该线程是否正在独占资源。只有用到condition才需要去实现它。</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>什么是钩子方法呢？</strong> 钩子方法是一种被声明在抽象类中的方法，它可以是空方法（由子类实现），也可以是默认实现的方法。模板设计模式通过钩子方法控制固定步骤的实现。</p><p>除了上面提到的钩子方法之外，AQS 类中的其他方法都是 <code>final</code> ，所以无法被其他类重写。</p><p>以 <code>ReentrantLock</code> 为例，state 初始化为 0，表示未锁定状态。A 线程 <code>lock()</code> 时，会调用 <code>tryAcquire()</code> 独占该锁并将 <code>state+1</code> 。此后，其他线程再 <code>tryAcquire()</code> 时就会失败，直到 A 线程 <code>unlock()</code> 到 <code>state=</code>0（即释放锁）为止，其它线程才有机会获取该锁。当然，释放锁之前，A 线程自己是可以重复获取此锁的（state 会累加），这就是可重入的概念。但要注意，获取多少次就要释放多少次，这样才能保证 state 是能回到零态的。</p><p>再以 <code>CountDownLatch</code> 以例，任务分为 N 个子线程去执行，state 也初始化为 N（注意 N 要与线程个数一致）。这 N 个子线程是并行执行的，每个子线程执行完后<code> countDown()</code> 一次，state 会 CAS(Compare and Swap) 减 1。等到所有子线程都执行完后(即 <code>state=0</code> )，会 <code>unpark()</code> 主调用线程，然后主调用线程就会从 <code>await()</code> 函数返回，继续后余动作。</p><p>一般来说，自定义同步器要么是独占方法，要么是共享方式，他们也只需实现<code>tryAcquire-tryRelease</code>、<code>tryAcquireShared-tryReleaseShared</code>中的一种即可。但 AQS 也支持自定义同步器同时实现独占和共享两种方式，如<code>ReentrantReadWriteLock</code>。</p><h4 id="_5、aqs-组件总结" tabindex="-1"><a class="header-anchor" href="#_5、aqs-组件总结" aria-hidden="true">#</a> 5、AQS 组件总结</h4><ul><li><strong><code>Semaphore</code>(信号量)-允许多个线程同时访问：</strong> <code>synchronized</code> 和 <code>ReentrantLock</code> 都是一次只允许一个线程访问某个资源，<code>Semaphore</code>(信号量)可以指定多个线程同时访问某个资源。</li><li><strong><code>CountDownLatch </code>（倒计时器）：</strong> <code>CountDownLatch</code> 是一个同步工具类，用来协调多个线程之间的同步。这个工具通常用来控制线程等待，它可以让某一个线程等待直到倒计时结束，再开始执行。</li><li><strong><code>CyclicBarrier</code>(循环栅栏)：</strong> <code>CyclicBarrier</code> 和 <code>CountDownLatch</code> 非常类似，它也可以实现线程间的技术等待，但是它的功能比 <code>CountDownLatch</code> 更加复杂和强大。主要应用场景和 <code>CountDownLatch</code> 类似。<code>CyclicBarrier</code> 的字面意思是可循环使用（<code>Cyclic</code>）的屏障（<code>Barrier</code>）。它要做的事情是，让一组线程到达一个屏障（也可以叫同步点）时被阻塞，直到最后一个线程到达屏障时，屏障才会开门，所有被屏障拦截的线程才会继续干活。<code>CyclicBarrier</code> 默认的构造方法是 <code>CyclicBarrier(int parties)</code>，其参数表示屏障拦截的线程数量，每个线程调用 <code>await()</code> 方法告诉 <code>CyclicBarrier</code> 我已经到达了屏障，然后当前线程被阻塞。</li></ul><h4 id="_6、用过-countdownlatch-么-什么场景下用的" tabindex="-1"><a class="header-anchor" href="#_6、用过-countdownlatch-么-什么场景下用的" aria-hidden="true">#</a> 6、用过 CountDownLatch 么？什么场景下用的？</h4><p>我们要读取处理 6 个文件，这 6 个任务都是没有执行顺序依赖的任务，但是我们需要返回给用户的时候将这几个文件的处理的结果进行统计整理。</p><p>为此我们定义了一个线程池和 count 为 6 的<code>CountDownLatch</code>对象 。使用线程池处理读取任务，每一个线程处理完之后就将 count-1，调用<code>CountDownLatch</code>对象的 <code>await()</code>方法，直到所有文件读取完之后，才会接着执行后面的逻辑。</p><p>方案一：通过CountDownLatch来进行倒数</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CountDownLatchExample1</span> <span class="token punctuation">{</span>
    <span class="token comment">// 处理文件的数量</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> threadCount <span class="token operator">=</span> <span class="token number">6</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 创建一个具有固定线程数量的线程池对象（推荐使用构造方法创建）</span>
        <span class="token class-name">ExecutorService</span> threadPool <span class="token operator">=</span> <span class="token class-name">Executors</span><span class="token punctuation">.</span><span class="token function">newFixedThreadPool</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">final</span> <span class="token class-name">CountDownLatch</span> countDownLatch <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CountDownLatch</span><span class="token punctuation">(</span>threadCount<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> threadCount<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">final</span> <span class="token keyword">int</span> threadnum <span class="token operator">=</span> i<span class="token punctuation">;</span>
            threadPool<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>
                <span class="token keyword">try</span> <span class="token punctuation">{</span>
                    <span class="token comment">//处理文件的业务操作</span>
                    <span class="token comment">//......</span>
                <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
                    <span class="token comment">//表示一个文件已经被完成</span>
                    countDownLatch<span class="token punctuation">.</span><span class="token function">countDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>

            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        countDownLatch<span class="token punctuation">.</span><span class="token function">await</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        threadPool<span class="token punctuation">.</span><span class="token function">shutdown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;finish&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>方案2：可以使用 <code>CompletableFuture</code> 类来改进！Java8 的 <code>CompletableFuture</code> 提供了很多对多线程友好的方法，使用它可以很方便地为我们编写多线程程序，什么异步、串行、并行或者等待所有线程执行完任务什么的都非常方便。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">CompletableFuture</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Void</span><span class="token punctuation">&gt;</span></span> task1 <span class="token operator">=</span>
    <span class="token class-name">CompletableFuture</span><span class="token punctuation">.</span><span class="token function">supplyAsync</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token punctuation">{</span>
        <span class="token comment">//自定义业务操作</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token class-name">CompletableFuture</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Void</span><span class="token punctuation">&gt;</span></span> task6 <span class="token operator">=</span>
    <span class="token class-name">CompletableFuture</span><span class="token punctuation">.</span><span class="token function">supplyAsync</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token punctuation">{</span>
    <span class="token comment">//自定义业务操作</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token class-name">CompletableFuture</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Void</span><span class="token punctuation">&gt;</span></span> headerFuture<span class="token operator">=</span><span class="token class-name">CompletableFuture</span><span class="token punctuation">.</span><span class="token function">allOf</span><span class="token punctuation">(</span>task1<span class="token punctuation">,</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span>task6<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">try</span> <span class="token punctuation">{</span>
    headerFuture<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//......</span>
<span class="token punctuation">}</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;all done. &quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的代码还可以继续优化，当任务过多的时候，把每一个 task 都列出来不太现实，可以考虑通过循环来添加任务。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">//文件夹位置</span>
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> filePaths <span class="token operator">=</span> <span class="token class-name">Arrays</span><span class="token punctuation">.</span><span class="token function">asList</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span>
<span class="token comment">// 异步处理所有文件</span>
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">CompletableFuture</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> fileFutures <span class="token operator">=</span> filePaths<span class="token punctuation">.</span><span class="token function">stream</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>filePath <span class="token operator">-&gt;</span> <span class="token function">doSomeThing</span><span class="token punctuation">(</span>filePath<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">(</span><span class="token class-name">Collectors</span><span class="token punctuation">.</span><span class="token function">toList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 将他们合并起来</span>
<span class="token class-name">CompletableFuture</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Void</span><span class="token punctuation">&gt;</span></span> allFutures <span class="token operator">=</span> <span class="token class-name">CompletableFuture</span><span class="token punctuation">.</span><span class="token function">allOf</span><span class="token punctuation">(</span>
    fileFutures<span class="token punctuation">.</span><span class="token function">toArray</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">CompletableFuture</span><span class="token punctuation">[</span>fileFutures<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="_7、cas" tabindex="-1"><a class="header-anchor" href="#_7、cas" aria-hidden="true">#</a> 7、CAS</h3><h3 id="_1、什么是cas" tabindex="-1"><a class="header-anchor" href="#_1、什么是cas" aria-hidden="true">#</a> 1、什么是CAS?</h3><p>CAS全称 Compare And Swap，比较与交换，是乐观锁的主要实现方式。CAS 在不使用锁的情况下实现多线程之间的变量同步。ReentrantLock 内部的 AQS 和原子类内部都使用了 CAS。</p><p>CAS算法涉及到三个操作数：</p><ul><li>需要读写的内存值 V。</li><li>进行比较的值 A。</li><li>要写入的新值 B。</li></ul><p>只有当 V 的值等于 A 时，才会使用原子方式用新值B来更新V的值，否则会继续重试直到成功更新值。</p><p>以 AtomicInteger 为例，AtomicInteger 的 getAndIncrement()方法底层就是CAS实现，关键代码是compareAndSwapInt(obj, offset, expect, update) ，其含义就是，如果 obj 内的 value 和expect 相等，就证明没有其他线程改变过这个变量，那么就更新它为 update ，如果不相等，那就会继续重试直到成功更新值。</p><h3 id="_2、cas存在的问题" tabindex="-1"><a class="header-anchor" href="#_2、cas存在的问题" aria-hidden="true">#</a> 2、CAS存在的问题？</h3><p><strong>CAS 三大问题</strong>：</p><ol><li><p><strong>ABA问题</strong>。CAS需要在操作值的时候检查内存值是否发生变化，没有发生变化才会更新内存值。但是如果内存值原来是A，后来变成了B，然后又变成了A，那么CAS进行检查时会发现值没有发生变化，但是实际上是有变化的。ABA问题的解决思路就是在变量前面添加版本号，每次变量更新的时候都把版本号加一，这样变化过程就从 A－B－A 变成了 1A－2B－3A 。JDK从1.5开始提供了AtomicStampedReference类来解决ABA问题，原子更新带有版本号的引用类 型。</p></li><li><p><strong>循环时间长开销大</strong>。CAS操作如果长时间不成功，会导致其一直自旋，给CPU带来非常大的开销。</p></li><li><p><strong>只能保证一个共享变量的原子操作</strong>。对一个共享变量执行操作时，CAS能够保证原子操作，但是对多个共享变量操作时，CAS是无法</p></li></ol><p>保证操作的原子性的。Java从1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性，可以把多个变量放在一个对象里</p><p>来进行CAS操作。</p><h3 id="_2、为什么cas那么快" tabindex="-1"><a class="header-anchor" href="#_2、为什么cas那么快" aria-hidden="true">#</a> 2、为什么CAS那么快？</h3><blockquote><p><a href="https://www.csdn.net/tags/MtTaIg0sODY2MDMzLWJsb2cO0O0O.html" target="_blank" rel="noopener noreferrer">多线程并发-synchronized和CAS锁的性能差别<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><p><a href="https://blog.csdn.net/No_Game_No_Life_/article/details/106100813" target="_blank" rel="noopener noreferrer">Java架构直通车——为什么线程切换会导致用户态与内核态的切换？<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><p><a href="https://blog.csdn.net/alex_xfboy/article/details/90722654?spm=1001.2101.3001.6661.1&amp;utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&amp;depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&amp;utm_relevant_index=1" target="_blank" rel="noopener noreferrer">基本功：线程上下文切换<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><p><a href="https://blog.csdn.net/lixinkuan328/article/details/94319775" target="_blank" rel="noopener noreferrer">CAS技术之底层原理<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>：完全依赖于硬件 功能,通过它实现了原子操作，CAS底层C++调用的汇编指令，汇编指令中对cache的缓存行锁，或数据超过64kb后膨胀升级的对总线的总线锁，即CAS在Java层面没有加锁，但在硬件层面上其实还是有加锁的。</p></blockquote><p>synchronized：若是多个线程调用同一个同步代码块(使用一个对象头来作为锁)，那么只能有一个来进行执行，其他的线程都会进行到阻塞状态。之后切换线程就会涉及到一个用户态与内核态的切换。</p><ul><li>因为线程的调度是在内核态运行的，而线程中的代码是在用户态运行。</li></ul><p>乐观锁：默认表示所有的线程不会发生冲突，保持乐观的一个心态，那么线程就不会出现阻塞的情况，每次操作都认为不会发生冲突，尝试执行，并检测结果是否正确。如果正确则执行成功，否则发生了冲突，回退再重新尝试直到没有冲突。其实重试时间很快，差不多几毫秒，这个线程在尝试的过程一直在cpu上跑，只是跑的是无用指令，那么就<strong>没有从用户态切换到内核态</strong>，开销因此变小。</p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>对比synchronized以及cas：
1、锁的概念：悲观锁、乐观锁
2、场景使用不同：synchronized适用于并发比较高的情况，cas常用在并发比较低的情况下。
3、原子范围：AS机制所保证的只是一个变量的原子性操作，而不能保证整个代码块的原子性。比如需要保证3个变量进行原子性的更新，就不得不使用Synchronized了。
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>总结：当并发量比较大是，sychronized的性能会比CAS块，当然当查询量很少是，可以直接执行CAS对应的指令，减少了上下文的缺陷，大大提升了工作效率。</strong></p><ul><li>若是并发量较大，那么很有可能多个线程会不断的进行重试，那么就会占用我们的cpu，那此时为了让cpu不被大量的无用重复的重试操作执行，那么可以使用synchronzied；若是并发数量较少的话，那么重试次数也少相较于sychronized上下文切换效率稍微更高一些。</li></ul><h3 id="_3、为什么concurrenthashmap中使用cas-synchronized" tabindex="-1"><a class="header-anchor" href="#_3、为什么concurrenthashmap中使用cas-synchronized" aria-hidden="true">#</a> 3、为什么concurrenthashmap中使用cas+synchronized？</h3><blockquote><p><a href="https://blog.csdn.net/wojiao228925661/article/details/98520706" target="_blank" rel="noopener noreferrer">ConcurrentHashMap 1.8为什么要使用CAS+Synchronized取代Segment+ReentrantLock<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><p><a href="https://blog.csdn.net/javaJasonjava/article/details/115785628" target="_blank" rel="noopener noreferrer">ConcurrentHashMap1.7的实现原理与使用<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p></blockquote><p>1.8以前的ConcurrentHashMap是怎么保证线程并发？</p><ul><li>在初始化ConcurrentHashMap的时候,会初始化一个Segment数组,容量为16,而每个Segment呢,都继承了ReentrantLock类,也就是说每个Segment类本身就是一个锁,之后Segment内部又有一个table数组,而每个table数组里的索引数据呢,又对应着一个Node链表。</li><li>put过程：首先,当我们使用put方法的时候,是对我们的key进行hash拿到一个整型,然后将整型对16取模,拿到对应的Segment,之后调用Segment的put方法,然后上锁,请注意,这里lock()的时候其实是this.lock(),也就是说,每个Segment的锁是分开的。</li><li>注意：一个上锁不会影响另一个,此时也就代表了我可以有十六个线程进来,而ReentrantLock上锁的时候如果只有一个线程进来,是不会有线程挂起的操作的,也就是说只需要在AQS里使用CAS改变一个state的值为1,此时就能对代码进行操作,这样一来,我们等于将并发量/16了。</li></ul><p>1.8的ConcurrentHashMap：</p><ul><li>获取node节点是cas操作；其中put是synchronized(f)，这个f就是对应哈希数组的指定下标链表，锁住的是hash冲突那条链表。</li></ul><p>问题1：如果使用ReentrantLock其实也可以将锁细化成这样的,只要让Node类继承ReentrantLock就行了,这样的话调用f.lock()就能做到和Synchronized(f)同样的效果,但为什么不这样做呢?</p><ul><li>锁已经被细化到这种程度了,那么出现并发争抢的可能性还高吗?还有就是,哪怕出现争抢了,只要线程可以在30到50次自旋里拿到锁,那么Synchronized就不会升级为重量级锁,而等待的线程也就不用被挂起,我们也就少了挂起和唤醒这个上下文切换的过程开销。</li><li>简易：也就是说当前哈希表锁住的已经很细化了，哪怕出现竞争，线程也能够在自旋时间中拿到锁，此时synchronized就不会升级为重量级锁，此时也就省了挂起与唤醒的时间开销。</li></ul><p>问题2：如果是ReentrantLock呢?</p><ul><li>只有在线程没有抢到锁,然后新建Node节点后再尝试一次而已,不会自旋,而是直接被挂起。</li><li>问题：我们就很容易会多出线程上下文开销的代价.当然,你也可以使用tryLock(),但是这样又出现了一个问题,你怎么知道tryLock的时间呢?在时间范围里还好,假如超过了呢?</li></ul><p>总结：锁被细化到如此程度上,使用Synchronized是最好的选择。</p><ul><li>Synchronized和ReentrantLock他们的开销差距是在释放锁时唤醒线程的数量 <ul><li>Synchronized是唤醒锁池里所有的线程+刚好来访问的线程。 <ul><li>这是JVM层面的实现，Synchronized被持有锁对象的线程使用完毕后，会让entryList里面阻塞的所有线程唤醒去参与锁的竞争，这也是说synchronized是非公平锁的原因，ReentrantLock可以在构造的时候通过参数选择是公平锁还是非公平锁的实现，默认是非公平的，ReentrantLock是Java api层面的实现。</li></ul></li><li>ReentrantLock则是当前线程后进来的第一个线程+刚好来访问的线程（公平锁）。</li></ul></li></ul><hr><h2 id="_3、代码题" tabindex="-1"><a class="header-anchor" href="#_3、代码题" aria-hidden="true">#</a> 3、代码题</h2><h3 id="_1、线程通信小例子-交替打印1-100" tabindex="-1"><a class="header-anchor" href="#_1、线程通信小例子-交替打印1-100" aria-hidden="true">#</a> 1、线程通信小例子(交替打印1-100)</h3><p>思路：synchronized + notify + wait操作，在synchronized中先进行notify()，在执行完i++后来进行一个wait()操作。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> 面试题<span class="token punctuation">;</span>

<span class="token doc-comment comment">/**
 * @Description: 线程通信小例子(交替打印1-100)
 * @Author: changlu
 * @Date: 2:33 PM
 */</span>
<span class="token keyword">class</span> <span class="token class-name">MyRunnable</span> <span class="token keyword">implements</span> <span class="token class-name">Runnable</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">int</span> i<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">&lt;</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token comment">//唤醒操作</span>
                    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    i<span class="token operator">++</span><span class="token punctuation">;</span>
                    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;: &quot;</span> <span class="token operator">+</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>

                    <span class="token comment">//进入等待</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">&lt;</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        <span class="token keyword">try</span> <span class="token punctuation">{</span>
                            <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token punctuation">}</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
                    <span class="token keyword">break</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AlternateDemo</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">MyRunnable</span> myRunnable <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyRunnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Thread</span> thread1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span>myRunnable<span class="token punctuation">)</span><span class="token punctuation">;</span>
        thread1<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">&quot;线程1&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Thread</span> thread2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span>myRunnable<span class="token punctuation">)</span><span class="token punctuation">;</span>
        thread2<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">&quot;线程2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        thread1<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        thread2<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="_2、生产者与消费者" tabindex="-1"><a class="header-anchor" href="#_2、生产者与消费者" aria-hidden="true">#</a> 2、生产者与消费者</h3><p>思路：将生产与消费方法统一写在一个员工类当中，对应的runnable有两个一个是生产者工作，另一个是消费者工作，两个runnable在构造的时候需要传入一个员工类来进行操作，思路也与1中一致，同样借助notify()与wait()来进行通知与阻塞。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> 面试题<span class="token punctuation">;</span>

<span class="token doc-comment comment">/**
 * @Description:
 * @Author: changlu
 * @Date: 2:50 PM
 */</span>
<span class="token keyword">class</span> <span class="token class-name">Clerk</span> <span class="token punctuation">{</span>
    <span class="token comment">//产品数量</span>
    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">int</span> product<span class="token punctuation">;</span>

    <span class="token comment">//生产产品</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">produceProduct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>product <span class="token operator">&lt;</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
           <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
               <span class="token keyword">if</span> <span class="token punctuation">(</span>product <span class="token operator">&lt;</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                   product<span class="token operator">++</span><span class="token punctuation">;</span>
                   <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;正在开始生产产品：&quot;</span> <span class="token operator">+</span> product<span class="token punctuation">)</span><span class="token punctuation">;</span>
                   <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
               <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
                   <span class="token comment">//若是数量&gt;100就不进行生产了，进入阻塞</span>
                   <span class="token keyword">try</span> <span class="token punctuation">{</span>
                       <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                   <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                       e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                   <span class="token punctuation">}</span>
               <span class="token punctuation">}</span>
           <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">//消费产品</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">consumerProduct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>product <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>product <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;正在消费产品：&quot;</span> <span class="token operator">+</span> product<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    product<span class="token operator">--</span><span class="token punctuation">;</span>
                    <span class="token comment">//进行唤醒</span>
                    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>product <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token comment">//进入阻塞</span>
                    <span class="token keyword">try</span> <span class="token punctuation">{</span>
                        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span>

            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>

<span class="token keyword">class</span> <span class="token class-name">Producer</span> <span class="token keyword">implements</span> <span class="token class-name">Runnable</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">Clerk</span> clerk<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">Producer</span> <span class="token punctuation">(</span><span class="token class-name">Clerk</span> clerk<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>clerk <span class="token operator">=</span> clerk<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            clerk<span class="token punctuation">.</span><span class="token function">produceProduct</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">class</span> <span class="token class-name">Consumer</span> <span class="token keyword">implements</span> <span class="token class-name">Runnable</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">Clerk</span> clerk<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">Consumer</span> <span class="token punctuation">(</span><span class="token class-name">Clerk</span> clerk<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>clerk <span class="token operator">=</span> clerk<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            clerk<span class="token punctuation">.</span><span class="token function">consumerProduct</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProducerAndConsumerDemo</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">Clerk</span> clerk <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Clerk</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Producer</span> producer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Producer</span><span class="token punctuation">(</span>clerk<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Consumer</span> consumer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Consumer</span><span class="token punctuation">(</span>clerk<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Thread</span> thread1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span>producer<span class="token punctuation">,</span> <span class="token string">&quot;线程1&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Thread</span> thread2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span>consumer<span class="token punctuation">,</span> <span class="token string">&quot;线程2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        thread1<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        thread2<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="_3、线程执行顺序怎么控制" tabindex="-1"><a class="header-anchor" href="#_3、线程执行顺序怎么控制" aria-hidden="true">#</a> 3、线程执行顺序怎么控制？</h3><p><strong>思路</strong>：利用join方法，指定线程.join()，效果就是当前线程阻塞，先让指定线程来执行，这样就能够控制线程的执行顺序。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> 面试题<span class="token punctuation">;</span>

<span class="token doc-comment comment">/**
 * @Description: 控制执行顺序demo
 * @Author: changlu
 * @Date: 3:37 PM
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ExecutionSequenceDemo</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">Thread</span> spring <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">SeasonThreadTask</span><span class="token punctuation">(</span><span class="token string">&quot;春天&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Thread</span> summer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">SeasonThreadTask</span><span class="token punctuation">(</span><span class="token string">&quot;夏天&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Thread</span> autumn <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">SeasonThreadTask</span><span class="token punctuation">(</span><span class="token string">&quot;秋天&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token comment">//夏天线程再启动</span>
            summer<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">//主线程等待线程summer执行完，再往下执行</span>
            summer<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">//春天线程先启动</span>
            spring<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">//主线程等待线程spring执行完，再往下执行</span>
            spring<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">//秋天线程最后启动</span>
            autumn<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">//主线程等待线程autumn执行完，再往下执行</span>
            autumn<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">class</span> <span class="token class-name">SeasonThreadTask</span> <span class="token keyword">implements</span> <span class="token class-name">Runnable</span><span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span>
    <span class="token keyword">public</span> <span class="token class-name">SeasonThreadTask</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span><span class="token number">4</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">+</span> <span class="token string">&quot;来了: &quot;</span> <span class="token operator">+</span> i <span class="token operator">+</span> <span class="token string">&quot;次&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">try</span> <span class="token punctuation">{</span>
                <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="_4、手写reentrantlock核心" tabindex="-1"><a class="header-anchor" href="#_4、手写reentrantlock核心" aria-hidden="true">#</a> 4、手写ReentrantLock核心</h3><p><strong>思路</strong>：定义一个链表队列，一个Thread当前类以及一个枪锁数量，方便之后可以进行可重入。</p><ul><li><code>LockSupport.park()</code>、<code>LockSupport.poll()</code>进入到阻塞状态；<code>LockSupport.unpark(thread)</code>;</li></ul><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206271549700.png" alt="image-20220627154901622" loading="lazy"></p><p>可重入实现：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DiyLock2</span> <span class="token keyword">implements</span> <span class="token class-name">Lock</span> <span class="token punctuation">{</span>

    <span class="token comment">//设置一个阻塞队列</span>
    <span class="token keyword">private</span> <span class="token class-name">LinkedBlockingQueue</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Thread</span><span class="token punctuation">&gt;</span></span> queue <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LinkedBlockingQueue</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">//可重入，将AtomiceReference替换为Thread</span>
    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token class-name">Thread</span> owner <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

    <span class="token comment">//新增属性：记录抢锁的数量</span>
    <span class="token keyword">private</span> <span class="token class-name">AtomicInteger</span> count <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AtomicInteger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">//枪锁失败，添加到队列中</span>
            <span class="token class-name">Thread</span> current <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">//线程进入到等待队列</span>
<span class="token comment">//            queue.add(current);</span>
            <span class="token comment">//用于查看添加到队列的顺序，一定是要强一致的</span>
            <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token class-name">DiyLock2</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                queue<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>current<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;Thread:&quot;</span> <span class="token operator">+</span> current<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;已经添加到队列&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//用于查看添加的顺序</span>
            <span class="token punctuation">}</span>
            <span class="token comment">//循环</span>
            <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
                <span class="token class-name">Thread</span> head <span class="token operator">=</span> queue<span class="token punctuation">.</span><span class="token function">peek</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//获取到队首的线程</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>current <span class="token operator">==</span> head<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token comment">//1、队首的线程来尝试抢10次进入阻塞</span>
<span class="token comment">//                    for(int num=0;num &lt; 10;num++){</span>
<span class="token comment">//                        //若是当前线程在线程的头部，那么就再次尝试去抢</span>
<span class="token comment">//                        if (!tryLock()) {</span>
<span class="token comment">//                            if (num == 9) {</span>
<span class="token comment">//                                //枪锁失败，就进入到阻塞中</span>
<span class="token comment">//                                LockSupport.park();</span>
<span class="token comment">//                            }</span>
<span class="token comment">//                        }else {</span>
<span class="token comment">//                            //枪锁成功，线程出队列</span>
<span class="token comment">//                            queue.poll();</span>
<span class="token comment">//                            return;</span>
<span class="token comment">//                        }</span>
<span class="token comment">//                    }</span>
                    <span class="token comment">//2、队首线程尝试抢依次进入阻塞（只判断一次）</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        <span class="token comment">//枪锁失败，就进入到阻塞中</span>
                        <span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">park</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
                        <span class="token comment">//枪锁成功，线程出队列</span>
                        queue<span class="token punctuation">.</span><span class="token function">poll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token keyword">return</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
                    <span class="token comment">//不在队头，直接给你挂起</span>
                    <span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">park</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token doc-comment comment">/**
     * 在抢锁的过程中进行可重入的判断，依据的就是抢占锁的次数
     * <span class="token keyword">@return</span> true：上锁成功；false：上锁失败。
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">Thread</span> current <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//抢锁的次数</span>
        <span class="token keyword">int</span> counts <span class="token operator">=</span> count<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//若是&gt;0说明当前有线程已经抢到了</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>counts <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">//如果锁是自己本身</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>current <span class="token operator">==</span> owner<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">//重入次数+1</span>
                count<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>counts <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{</span>
                <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
            <span class="token comment">//次数为0，意味着没有线程抢到锁，使用CAS来抢锁</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>count<span class="token punctuation">.</span><span class="token function">compareAndSet</span><span class="token punctuation">(</span>counts<span class="token punctuation">,</span> counts <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">//若是抢到锁</span>
                owner <span class="token operator">=</span> current<span class="token punctuation">;</span>
                <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
                <span class="token comment">//抢锁失败</span>
                <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token doc-comment comment">/**
     * 主要做一个线程的释放操作
     */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">tryUnlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">//(1)公平</span>
            <span class="token comment">//若是成功解锁，那么就唤醒头部线程队列</span>
<span class="token comment">//            Thread head = queue.peek();</span>
<span class="token comment">//            if (head != null) {</span>
<span class="token comment">//                LockSupport.unpark(head);</span>
<span class="token comment">//            }</span>
            <span class="token comment">//(2)非公平</span>
            <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Object</span> o <span class="token operator">:</span> queue<span class="token punctuation">.</span><span class="token function">toArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">Thread</span> thread <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">)</span> o<span class="token punctuation">;</span>
                <span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">unpark</span><span class="token punctuation">(</span>thread<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token doc-comment comment">/**
     * 进行锁的次数以及当前锁控制
     * <span class="token keyword">@return</span>
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">tryUnlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token class-name">Thread</span> current <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//判断是否是当前线程</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>owner <span class="token operator">!=</span> current<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">//若不是当前线程，直接抛出异常</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalMonitorStateException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
            <span class="token keyword">final</span> <span class="token keyword">int</span> counts <span class="token operator">=</span> count<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">int</span> next <span class="token operator">=</span> counts <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
            <span class="token comment">//若是为0表示当前要进行解锁了</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>next <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                owner <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
                count<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>next<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
                <span class="token comment">//若next不为0，意味者还有重入的锁没有解，修改count即可，owner不变</span>
                count<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>next<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">lockInterruptibly</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>

    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token keyword">long</span> time<span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span> unit<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Condition</span> <span class="token function">newCondition</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="_5、手写线程池" tabindex="-1"><a class="header-anchor" href="#_5、手写线程池" aria-hidden="true">#</a> 5、手写线程池</h3><blockquote><p><a href="https://blog.csdn.net/hongtaolong/article/details/87808009" target="_blank" rel="noopener noreferrer">并发编程之手写一个简单的线程池<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p></blockquote><p>思路：存储线程容器Set + 存储任务队列容器BlockQueue。</p><ul><li>初始化线程池：实际上就是启动传入的核心线程数量的线程，whlie条件为interrupted()，从阻塞队列中取使用的是take()方法，这个方法在队列为空的情况下会阻塞住。</li><li>执行execute()：实际上就是将任务添加到队列中。</li><li>关闭线程池：从集合中取出所有的线程调用自定义的销毁方法（这个销毁方法实际上走的就是一个interrupt()打断方法，本质就是让run结束）</li></ul><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>changlu<span class="token punctuation">.</span></span>线程池<span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">HashSet</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Set</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span></span><span class="token class-name">ArrayBlockingQueue</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span></span><span class="token class-name">BlockingQueue</span></span><span class="token punctuation">;</span>

<span class="token doc-comment comment">/**
 * @Description: 自定义线程池
 * @Author: changlu
 * @Date: 1:21 PM
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyThreadPool</span> <span class="token punctuation">{</span>

    <span class="token comment">//默认线程池中线程的数量</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> WORK_NUM <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>

    <span class="token comment">//默认处理任务数量</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> TASK_NUM <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span>

    <span class="token comment">//存放任务</span>
    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">BlockingQueue</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Runnable</span><span class="token punctuation">&gt;</span></span> taskQueue<span class="token punctuation">;</span>

    <span class="token comment">//保存线程的集合</span>
    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">WorkThread</span><span class="token punctuation">&gt;</span></span> workThreads<span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token keyword">int</span> workNumber<span class="token punctuation">;</span><span class="token comment">//线程数量</span>

    <span class="token keyword">private</span> <span class="token keyword">int</span> taskNumber<span class="token punctuation">;</span><span class="token comment">//任务数量</span>

    <span class="token keyword">public</span> <span class="token class-name">MyThreadPool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">(</span>WORK_NUM <span class="token punctuation">,</span> TASK_NUM<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token class-name">MyThreadPool</span><span class="token punctuation">(</span><span class="token keyword">int</span> workNumber <span class="token punctuation">,</span> <span class="token keyword">int</span> taskNumber<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>taskNumber<span class="token operator">&lt;=</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            taskNumber <span class="token operator">=</span> TASK_NUM<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>workNumber<span class="token operator">&lt;=</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            workNumber <span class="token operator">=</span> WORK_NUM<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">//创建一个数组阻塞队列</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>taskQueue <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayBlockingQueue</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Runnable</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>taskNumber<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>workNumber <span class="token operator">=</span> workNumber<span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>taskNumber <span class="token operator">=</span> taskNumber<span class="token punctuation">;</span>

        workThreads <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashSet</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">WorkThread</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//工作线程处理好了，启动一定数量的线程数，从队列中获取任务处理</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> workNumber<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">WorkThread</span> workThread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WorkThread</span><span class="token punctuation">(</span><span class="token string">&quot;mythreadpool_&quot;</span> <span class="token operator">+</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>
            workThread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            workThreads<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>workThread<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token doc-comment comment">/**
     * 线程池执行任务方法：本质就是向阻塞队列中添加任务
     * <span class="token keyword">@param</span> <span class="token parameter">task</span>
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token class-name">Runnable</span> task<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            taskQueue<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>task<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">//销毁线程池</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;ready close pool&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">WorkThread</span> workThread <span class="token operator">:</span> workThreads<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            workThread<span class="token punctuation">.</span><span class="token function">stopWorker</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            workThread <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span><span class="token comment">//help gc</span>
        <span class="token punctuation">}</span>
        <span class="token comment">//清楚所有元素</span>
        workThreads<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>


    <span class="token comment">//工作线程实现</span>
    <span class="token keyword">private</span> <span class="token keyword">class</span> <span class="token class-name">WorkThread</span> <span class="token keyword">extends</span> <span class="token class-name">Thread</span> <span class="token punctuation">{</span>
        <span class="token keyword">public</span> <span class="token class-name">WorkThread</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token function">setName</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">//检测是否被打断</span>
            <span class="token keyword">while</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">interrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">try</span> <span class="token punctuation">{</span>
                    <span class="token class-name">Runnable</span> runnable <span class="token operator">=</span> taskQueue<span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//若是该线程执行了interrupt()这里就会抛出异常。（其他情况包含： notify（））</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span>runnable <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">&quot; ready execute:&quot;</span><span class="token operator">+</span>runnable<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        runnable<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span>
                    runnable <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span><span class="token comment">//help GC</span>
                <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//很关键，在检测出异常时，还应该进行打断，这样才能够让run()方法停止</span>
                    e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">stopWorker</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">//打断</span>
            <span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>测试：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>changlu<span class="token punctuation">.</span></span>线程池<span class="token punctuation">;</span>

<span class="token doc-comment comment">/**
 * @Description: 自定义线程池任务
 * @Author: changlu
 * @Date: 1:33 PM
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">MyThreadPool</span> myThreadPool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyThreadPool</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Runnable</span> runnable <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;exec ...&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
        myThreadPool<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span>runnable<span class="token punctuation">)</span><span class="token punctuation">;</span>
        myThreadPool<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span>runnable<span class="token punctuation">)</span><span class="token punctuation">;</span>
        myThreadPool<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span>runnable<span class="token punctuation">)</span><span class="token punctuation">;</span>
        myThreadPool<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span>runnable<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//终止线程</span>
        myThreadPool<span class="token punctuation">.</span><span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206271556049.png" alt="image-20220626135754845" loading="lazy"></p></div><!----><footer class="page-meta"><div class="meta-item edit-link"><a href="https://gitee.com/changluJava/personal-reading/edit/main/demo/src/zh/interview/JUC.md" rel="noopener noreferrer" target="_blank" aria-label="编辑此页" class="nav-link label"><!--[--><svg xmlns="http://www.w3.org/2000/svg" class="icon edit-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="edit icon"><path d="M430.818 653.65a60.46 60.46 0 0 1-50.96-93.281l71.69-114.012 7.773-10.365L816.038 80.138A60.46 60.46 0 0 1 859.225 62a60.46 60.46 0 0 1 43.186 18.138l43.186 43.186a60.46 60.46 0 0 1 0 86.373L588.879 565.55l-8.637 8.637-117.466 68.234a60.46 60.46 0 0 1-31.958 11.229z"></path><path d="M728.802 962H252.891A190.883 190.883 0 0 1 62.008 771.98V296.934a190.883 190.883 0 0 1 190.883-192.61h267.754a60.46 60.46 0 0 1 0 120.92H252.891a69.962 69.962 0 0 0-69.098 69.099V771.98a69.962 69.962 0 0 0 69.098 69.098h475.911A69.962 69.962 0 0 0 797.9 771.98V503.363a60.46 60.46 0 1 1 120.922 0V771.98A190.883 190.883 0 0 1 728.802 962z"></path></svg><!--]-->编辑此页<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div><!----><!----></footer><nav class="page-nav"><a href="/zh/interview/Java%E5%AE%B9%E5%99%A8.html" class="nav-link prev" aria-label="Java容器"><div class="hint"><span class="arrow left"></span>上一页</div><div class="link"><span class="icon iconfont icon-lock" style=""></span>Java容器</div></a><a href="/zh/interview/JVM.html" class="nav-link next" aria-label="JVM"><div class="hint">下一页<span class="arrow right"></span></div><div class="link">JVM<span class="icon iconfont icon-lock" style=""></span></div></a></nav><div class="giscus-wrapper input-top" style="display:block;"><div style="text-align:center">Loading...</div></div><!----><!--]--></main><!--]--><footer class="footer-wrapper"><div class="footer">默认页脚</div><div class="copyright">Copyright © 2022 长路</div></footer><!--]--></div><!--]--><!----><!--]--></div>
    <script type="module" src="/assets/app.e732cc94.js" defer></script>
  </body>
</html>
